博客主页android
MVC:Model-View-Controller,经典模式,很容易理。数据库
可是在Android实际开发中,这个View层对应于布局文件,其实能作的事情特别少,实际上关于该布局文件中的数据绑定操做,事件处理的代码都在Activity中;咱们每每也会把具体的业务相关代码放到了Activity中;再加上Activity自己又承担着控制层的责任,这样致使Contrlller层愈来愈臃肿。segmentfault
因此说,MVC真实存在的是MC(V),Controller与Model根本就分不开,View和Model严重耦合。服务器
从图中能够看出,Controller是做为媒介,处于Model和View之间。Model和View之间有紧密的联系,耦合性偏强。网络
MVC主要缺点有两个:架构
优势:异步
举一个简单的例子:获取网络图片并展现在界面上ide
public interface ImageModel { // 从网络加载图片 void loadImage(String imagePath, OnImageListener listener); interface OnImageListener { void shopImage(Bitmap bitmap); } } public class ImageModelImpl implements ImageModel { @Override public void loadImage(String imagePath, OnImageListener listener) { if (listener != null && !TextUtils.isEmpty(imagePath)) { // 模拟网络获取图片 if (!TextUtils.isEmpty(imagePath)) { listener.shopImage(BitmapFactory.decodeFile(imagePath)); } else { listener.shopImage(null); } } } }
public class MainActivity extends AppCompatActivity implements ImageModel.OnImageListener { private static final String TAG = "===>"; // View层 private ImageView mShowImageView; // Model层 private ImageModel mImageModel; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mShowImageView = findViewById(R.id.showImageView); findViewById(R.id.loadImageBtn).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // 加载图片 mImageModel.loadImage("/mnt/sdcard/Pictures/2.png", MainActivity.this); } }); mImageModel = new ImageModelImpl(); } @Override public void shopImage(Bitmap bitmap) { if (bitmap != null) { // 展现图片 mShowImageView.setImageBitmap(bitmap); } } }
MVP:Model-View-Presenter,MVC的一个演变模式,将Controller换成了Presenter,主要为了解决上述第一个缺点,将View和Model解耦,不过第二个缺点依然没有解决。函数
一、 MVP接口过多
二、 每个功能,相对于MVC要多写好几个文件
三、 若是某一个界面中须要请求多个服务器接口,这个界面文件中会实现不少的回调接口,致使代码繁杂
四、 若是更改了数据源和请求中参数,会致使更多的代码修改
五、 额外的代码复杂度及学习成本布局
一、 减小了Activity的职责,简化了Activity中的代码,将复杂的逻辑代码提取到了Presenter中进行处理。与之对应的好处就是:耦合度更低
二、 Activity代码变得更加简洁:使用MVP以后,Activity就能瘦身许多了,基本上只有findView、setListener以及init的代码。其余的就是对Presenter的调用,还有对View接口的实现。这种情形下阅读代码就容易多了,并且你只要看Presenter的接口,就能明白这个模块都有哪些业务,很快就能定位到具体代码。Activity变得容易看懂,容易维护,之后要调整业务。删减功能也就变得简单许多。
三、 方便进行单元测试
四、 避免Activity的内存泄露
Java一个强大的功能就是其虚拟机的内存回收机制,这个功能使得Java用户在设计代码的时候,不用像C++用户那样考虑对象的回收问题。然而,Java用户老是喜欢随便写一大堆对象,而后幻想着虚拟机能帮他们处理好内存的回收工做。但是虚拟机在回收内存的时候,只会回收那些没有被引用的对象,被引用着的对象由于还可能会被调用,因此不能回收
Activity是有生命周期的,用户随时可能切换Activity,当APP的内存不够用的时候,系统会回收处于后台的Activity的资源以免OOM。
五、 模块职责划分明显,层次清晰,接口功能清晰
六、 Model层和View层分离,解耦;修改View而不影响Model
七、 功能复用度高,方便;一个Presenter能够复用于多个View,而不用更改Presenter的逻辑
八、 若是后台接口还未写好,但已知返回数据类型的状况下,彻底能够写出此接口完整的功能
一、View:负责绘制UI元素,与用户进行交互(在Android中体现为Activity)
二、Activity interface:须要View实现的接口,View经过View interface与Presenter进行交互,下降耦合,方便进行单元测试
三、Model:负责存储、检索、操纵数据(有时也实现一个Model interface用来下降耦合)
四、Presenter:做为View与Model交互的中间纽带,处理与用户交互的负责逻辑
从服务器端下拉最新的20篇文章,而后将每一篇文章的简介显示到列表上,当用户点击某项数据进入到另外一个页面,该页面加载这篇文章的详细内容。
一、ArticleModel就是Model层接口
public interface ArticleModel { // 加载文章数据 void loadArticles(OnArticleListener listener); interface OnArticleListener { void onLoadComplete(List<Article> data); } }
二、ArticleModelImpl实现了ArticleModel接口,用于加载网络数据,为了代码简单,这里睡眠2秒模拟从网络获取数据
public class ArticleModelImpl implements ArticleModel { @Override public void loadArticles(OnArticleListener listener) { new LoadArticleTask(listener).execute(); } private static class LoadArticleTask extends AsyncTask<Void, Void, List<Article>> { private final OnArticleListener listener; LoadArticleTask(OnArticleListener listener) { this.listener = listener; } @Override protected List<Article> doInBackground(Void... params) { // 模拟网络请求 SystemClock.sleep(2000); final List<Article> data = new ArrayList<>(); for (int i = 0; i < 40; i++) { data.add(new Article("title-" + i, "message:" + i)); } return data; } @Override protected void onPostExecute(List<Article> data) { if (listener != null) { listener.onLoadComplete(data); } } } }
三、 ArticleViewInterface就是主界面的逻辑接口,表明View接口角色,用于Presenter回调View的操做
public interface ArticleViewInterface { void showProgressBar(); // 显示进度条 void hideProgressBar(); // 隐藏进度条 void showArticles(List<Article> data); // 展现数据 }
四、Presenter层,做为View和Model的中间人。
public interface ArticlePresenter { void loadArticles(); } public class ArticlePresenterImpl implements ArticlePresenter { // ArticleView的接口,表明了View角色 private ArticleViewInterface mView; // 文章数据的Model,也就是Model角色 private ArticleModel mArticleModel; public ArticlePresenterImpl(ArticleViewInterface view) { this.mView = view; mArticleModel = new ArticleModelImpl(); } // 获取文章,也就是咱们的业务逻辑 @Override public void loadArticles() { mView.showProgressBar(); mArticleModel.loadArticles(new ArticleModel.OnArticleListener() { @Override public void onLoadComplete(List<Article> data) { // 数据加载完后,通知View层更新UI mView.hideProgressBar(); mView.showArticles(data); } }); } }
五、ArticleActivity须要实现ArticleViewInterface接口,而且须要创建与Presenter的联系,ArticleActivity的业务逻辑都交给Presenter进行处理,处理结果经过ArticleViewInterface接口回调给ArticleActivity类
public class ArticleActivity extends AppCompatActivity implements ArticleViewInterface { private ProgressBar mProgressBar; private ArrayAdapter<Article> mAdapter; private ArticlePresenter mArticlePresenter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initView(); // 构建ArticlePresenter,与ArticleActivity创建关联 mArticlePresenter = new ArticlePresenterImpl(this); } private void initView() { mProgressBar = findViewById(R.id.load_progress_bar); ListView listView = findViewById(R.id.list_view); mAdapter = new ArrayAdapter<>(this, R.layout.item_list, R.id.item_title); listView.setAdapter(mAdapter); } @Override protected void onResume() { super.onResume(); // 请求文章数据 mArticlePresenter.loadArticles(); } @Override public void showArticles(List<Article> data) { mAdapter.setNotifyOnChange(true); mAdapter.addAll(data); // 更新UI } // .... }
因为Presenter常常须要执行一些耗时操做,如请求网络数据,而Presenter持有了ArticleActivity的强引用,若是在请求结束以前Activity被销毁了,那么因为网络请求尚未返回,致使Presenter一直持有ArticleActivity对象,使得ArticleActivity对象没法被回收,此时就发生内存泄露。
如何解决这样的问题呢?
咱们能够经过弱引用和Activity、Fragment的生命周期来解决这个问题。
一、 首先创建一个Presenter抽象,BasePresenter,它是一个泛型类,泛型类型为View角色要实现的接口类型
public abstract class BasePresenter<V> { private Reference<V> mViewRef; // View接口类型的弱引用 public void attachView(V view) { mViewRef = new WeakReference<>(view); // 创建关联 } public void detachView() { if (mViewRef != null) { mViewRef.clear(); mViewRef = null; } } public boolean isViewAttached() { return mViewRef != null && mViewRef.get() != null; } protected V getView() { return mViewRef.get(); } }
二、 建立一个MVPBaseActivity基类,经过这个基类的生命周期函数来控制它与Presenter的关系。MVPBaseActivity有两个泛型参数,第一个是View的接口类型,第二个是Presneter的具体类型
public abstract class MVPBaseActivity<V, T extends BasePresenter<V>> extends AppCompatActivity{ protected T mPresenter; // Presenter对象 @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); mPresenter = createPresenter(); // 建立Presenter mPresenter.attachView((V) this); } @Override protected void onDestroy() { super.onDestroy(); mPresenter.detachView(); } protected abstract T createPresenter(); }
若是个人文章对您有帮助,不妨点个赞鼓励一下(^_^)