2025年6月8日 星期日 乙巳(蛇)年 三月十二 设为首页 加入收藏
rss
您当前的位置:首页 > 计算机 > 编程开发 > 安卓(android)开发

MVP模式——Okhttp实现下载图片并带有进度 【Android Demo】

时间:01-14来源:作者:点击数:42

前言

MVP 是 MVC 的变种,其实是一种升级。要说 MVP 就要说说 MVC,在 MVC 中 Activity 其实是 View层级,但是通常在使用中 Activity即是View也是Controller,并没有将 View层 和 Controller层 进行分离, 耦合度大大提高,非常不利于项目的管理。这时候 MVP 就应运而生了。

核心思想

MVP:Model,View,Presenter

MVP 把 Activity 中的 UI逻辑 抽象成 View接口,把 业务逻辑 抽象成 Presenter接口,Model类 还是原来的 Model。在 MVP 模式中 Activity 的功能就是响应生命周期和显示界面,具体其他的工作都丢到了 Presenter层 中进行完成,Presenter 其实是 Model层 和 View层 的桥梁。

Demo

MVP 模式所做的事情很简单,就是将业务逻辑和视图逻辑抽象到接口中。

怎么理解呢,我们就根据此次要实现的下载功能,用代码说话。

定义Model,View,Presenter 接口

IDownloadModel

Model层也可以叫做数据提供层

在我们的下载任务中,业务逻辑只有一个,就是下载

  • public interface IDownloadModel {
  • /**
  • * 下载操作
  • * @param url
  • */
  • void download(String url);
  • }
IDownloadView

View 接口定义所有需要实现的视图逻辑

  • public interface IDownloadView {
  • /**
  • * 显示进度条
  • * @param show
  • */
  • void showProgressBar(boolean show);
  • /**
  • * 设置进度条进度
  • * @param progress
  • */
  • void setProcessProgress(int progress);
  • /**
  • * 根据数据设置view
  • * @param result
  • */
  • void setView(Bitmap result);
  • /**
  • * 设置请求失败时的view
  • */
  • void showFailToast();
  • }
IDownloadPresenter

因为在之前写的时候,定义了四个方法。后来考虑到model和presenter并不是双向持有,model不会 持有presenter,所以定义了一个主逻辑就是下载,在model中采用接口回调的方式通知presenter。

  • public interface IDownloadPresenter {
  • /**
  • * 下载
  • *
  • * @param url
  • */
  • void download(String url);
  • }

Model,View,Presenter 的具体实现

DownloadModel

采用了okhttp的异步get请求网络,因为回调方法是在子线程中的,所以做最好要回到主线程传递信息

  • public class DownloadModel implements IDownloadModel {
  • private DownloadListener listener;
  • private Handler mHandler = new Handler(Looper.getMainLooper());
  • public DownloadModel(DownloadListener listener) {
  • this.listener = listener;
  • }
  • @Override
  • public void download(String url) {
  • OkHttpClient okHttpClient = new OkHttpClient();
  • Request request = new Request.Builder()
  • .get().url(url).build();
  • Call call = okHttpClient.newCall(request);
  • call.enqueue(new Callback() {
  • @Override
  • public void onFailure(Call call, IOException e) {
  • mHandler.post(new Runnable() {
  • @Override
  • public void run() {
  • listener.failed();
  • }
  • });
  • }
  • @Override
  • public void onResponse(Call call, Response response) throws IOException {
  • File file = new File("/data/data/com.example.mvp_okhttp", "hh.png");
  • InputStream in = response.body().byteStream();
  • long total = response.body().contentLength();
  • WriteInputStreamUntils.WriteStreamToFile(in, file, total, listener);
  • mHandler.post(new Runnable() {
  • @Override
  • public void run() {
  • listener.downloadSuccess(file.getAbsolutePath());
  • }
  • });
  • }
  • });
  • }
  • public interface DownloadListener {
  • void downloadSuccess(String path);
  • void failed();
  • void refreshProgress(int progress);
  • }
  • }
DownloadPresenter

在Presenter具体实现中,业务相关的操作由Model去完成(例如download),视图相关的操作由View去完成

(如setView等)。Presenter 作为桥梁的作用就这样体现出来了,巧妙的将View和Model的具体实现连接了起来。

  • public class DownloadPresenter implements IDownloadPresenter, DownloadModel.DownloadListener {
  • private IDownloadView miDownloadView;
  • private final IDownloadModel downloadModel;
  • public DownloadPresenter(IDownloadView iDownloadView) {
  • downloadModel = new DownloadModel(this);
  • miDownloadView = iDownloadView;
  • }
  • @Override
  • public void download(String url) {
  • downloadModel.download(url);
  • }
  • @Override
  • public void downloadSuccess(String result) {
  • miDownloadView.showProgressBar(false);
  • Bitmap bitmap = BitmapFactory.decodeFile(result);
  • miDownloadView.setView(bitmap);
  • }
  • @Override
  • public void failed() {
  • miDownloadView.showProgressBar(false);
  • miDownloadView.showFailToast();
  • }
  • @Override
  • public void refreshProgress(int progress) {
  • miDownloadView.showProgressBar(true);
  • miDownloadView.setProcessProgress(progress);
  • }
  • }
MainActivity

1.Button的click方法负责发起下载任务,但又不负责具体实现,而是由Presenter转接给Model去实现

2.Activity 什么时候显示ProgressDialog,什么时候显示Toast直接由Presenter告诉他,他只做一个View想做的事情

3.Activity里没有任何逻辑处理,所有的逻辑判断都在Model中完成了

  • public class MainActivity extends AppCompatActivity implements IDownloadView {
  • private IDownloadPresenter downloadPresenter;
  • private Button button;
  • private ImageView imageView;
  • private String path1="https://cdn.wallpaperhub.app/cloudcache/e/f/1/6/c/3/ef16c3d491975175f2fbb1e24415724371c1c119.png";
  • private ProgressDialog progressDialog;
  • @Override
  • protected void onCreate(Bundle savedInstanceState) {
  • super.onCreate(savedInstanceState);
  • setContentView(R.layout.activity_main);
  • init();
  • }
  • private void init() {
  • downloadPresenter = new DownloadPresenter(this);
  • button = (Button) findViewById(R.id.btn);
  • imageView = (ImageView) findViewById(R.id.iv);
  • button.setOnClickListener(new View.OnClickListener() {
  • @Override
  • public void onClick(View v) {
  • downloadPresenter.download(path1);
  • }
  • });
  • progressDialog = new ProgressDialog(this);
  • progressDialog.setButton(DialogInterface.BUTTON_NEGATIVE, "Cancle", new DialogInterface.OnClickListener() {
  • @Override
  • public void onClick(DialogInterface dialog, int which) {
  • progressDialog.dismiss();
  • }
  • });
  • progressDialog.setCanceledOnTouchOutside(false);
  • progressDialog.setTitle("下载文件");
  • progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
  • }
  • @Override
  • public void showProgressBar(boolean show) {
  • if (show){
  • progressDialog.show();
  • }else {
  • progressDialog.dismiss();
  • }
  • }
  • @Override
  • public void setProcessProgress(int progress) {
  • progressDialog.setProgress(progress);
  • }
  • @Override
  • public void setView(Bitmap result) {
  • imageView.setImageBitmap(result);
  • Toast.makeText(MainActivity.this, "下载成功", Toast.LENGTH_SHORT).show();
  • }
  • @Override
  • public void showFailToast() {
  • Toast.makeText(MainActivity.this, "下载错误", Toast.LENGTH_SHORT).show();
  • }
  • }

总结

MVP固然好用

优点:

  • 结构十分清晰,实现解耦
  • 方便单元测试
  • 避免Activity内存泄露

APP发生 OOM 的最大原因就是出现内存泄露造成APP的内存不够用,而造成内存泄露的两大原因之一就是 Activity泄露(Activity Leak)(另一个原因是 Bitmap泄露(Bitmap Leak))。

转:Activity 是有生命周期的,用户随时可能切换 Activity,当APP的内存不够用的时候,系统会回收处于后台的Activity的资源以避免 OOM。

采用传统的模式,一大堆异步任务和对UI的操作都放在 Activity 里面,比如你可能从网络下载一张图片,在下载成功的回调里把图片加载到 Activity 的 ImageView 里面,所以异步任务保留着对 Activity 的引用。这样一来,即使 Activity 已经被切换到后台(onDestroy 已经执行),这些 异步任务 仍然保留着对 Activity 实例的引用, 所以系统就无法回收这个 Activity 实例了,结果就是 Activity Leak。

Android 的组件中,Activity 对象往往是在堆(Java Heap)里占最多内存的,所以系统会优先回收 Activity 对象, 如果有 Activity Leak,APP很容易因为内存不够而 OOM。

采用 MVP模式,只要在当前的 Activity 的 onDestroy 里,分离异步任务对Activity 的引用,就能避免 Activity Leak。

方便获取更多学习、工作、生活信息请关注本站微信公众号城东书院 微信服务号城东书院 微信订阅号
推荐内容
相关内容
栏目更新
栏目热门