androidMVP的尝试

在android项目开发中,随着功能不断迭代,代码量一般也会随之不断增长,维护成本愈来愈高。android

做为开发者,笔者常常会被杂乱的逻辑搞的焦头烂额,不由思考:什么样的结构可以简化开发,同时又能下降维护成本?git

当下开发中比较推崇的是三层架构,典型表明便是MVP。笔者在此将最近对MVP的理解与心得与你们分享一下。github

 

一直以来,笔者对android中MVP模式的理解并无很透彻,最近看了kymjs的文章《用MVP架构开发Android应用》,有一种醍醐灌顶的感受,特在此感谢做者。做者的MVP框架也放到了Github上——TheMVP,感兴趣的朋友能够多加关注。架构

 

就我的的理解,目前对MVP的分歧,主要在于Activity的归属问题上。大部分人认为Activity属于V层,但也有部分人认为Activity属于P层。app

Activity属于V层?

以登录页面为例,两个Edittext分别获取帐号和密码,一个Button用于登录。Activity首先setContentView,随后添加Button的点击监听,onClick中获取帐号和密码进行请求,一鼓作气。流程中setContentView,对Button进行监听,均须要对ui元素直接操做。如果复杂页面,则ui元素的直接操做将会更多,Activity做为V层有自然的优点。框架

Activity做为P层?

Activity中提供了很是多的回调方法,同时做为Context的实现类,各类Manager都可经过Activity来调用。能够说,咱们能想到的绝大部分逻辑操做都可以在Activity来完成,Activity也有做为P层的潜质。ide

 

既然Activity做为V层、P层均有必定道理,咱们又应该如何理解Activity呢?布局

Activity无所不能

Activity是上帝类,咱们在Activity中作任何事情都是能够的。ui

试想一下,在一个动态布局的页面中,咱们可能不须要xml来写布局,全部控件都是代码生成。各类事件也均有Activity来处理,其中也包括了file操做等。一个Activity将MVP的操做都作了,是否是很万能?this

  

咱们是否须要使用MV*模式?

仅从笔者的开发经验来看,对MV*模式的使用并很少,大部分状况下采用Activity/Fragment+Model层。

当咱们开发一个逻辑并不特别复杂的app时,只要抽象合理,代码应当不难维护,也没必要借助MV*模式了。

但随着PM的奇思妙想愈来愈多,项目越作越大,一个Activity可能几千行,各类逻辑交织,显得异常复杂。这时候咱们就能够考虑经过MV*来拯救咱们了!

换句话说,采用MV*模式自己也是一种无奈。业务过于复杂,只能经过拆分层次,将复杂的问题分而治之。

Activity在V层和P层哪一种更合理?

Activity由于过于全面,放在哪层均可以。不过正由于它无可替代,无论做为哪层,都须要取舍。

做为V层,则应该将非UI操做放到自定义的P层去。自定义P层自己不具有不少功能(譬如onDestroy释放handler等),这些都须要Activity提供接口实现。

做为P层,则须要将UI操做放到自定义的V层去,UI相关的操做由V层处理,P层不作干预。

 

笔者认为Activity做为P层较为方便,同时试着将Activity做为P层实现了一个比较简单且并不完善的MVP,仅供参考。

思路

M层没有给出,P层是继承于Activity的PresenterAdapter,V层是自定义的ViewAdapter。

P层的业务处理,不少都要反映在V层上,所以咱们的Activity持有ViewAdapter。

当页面较为复杂的时候,可能须要作不少UI处理,ViewAdapter提供各类接口给PresenterAdapter操做也是比较麻烦的。咱们可让P、V持有同一个状态集Info,P修改Info,V根据Info对UI进行渲染。

  • PresenterAdapter持有IView(主要为ViewAdapter实现类)和BaseInfo的实现类,初始化二者,并将BaseInfo绑定到IView上。
 1 /**
 2  * Created by puff on 2016/1/1.
 3  */
 4 public abstract class PresenterAdapter<T extends IView, U extends BaseInfo> extends AppCompatActivity implements IPresenter<T, U> {
 5 
 6     private T mView;
 7     private U mInfo;
 8 
 9     @Override
10     protected void onCreate(Bundle savedInstanceState) {
11         super.onCreate(savedInstanceState);
12         //初始化view和info,并关联
13         mView = initIView();
14         mInfo = initInfo();
15         mView.init(getLayoutInflater());
16         mView.setInfo(mInfo);
17         setContentView(mView.getRootView());
18     }
19 
20     @Override
21     public U getInfo() {
22         return mInfo;
23     }
24 
25     @Override
26     public T getView() {
27         return mView;
28     }

  • BaseInfo做为状态集,每对V/P均要实现一个。
 1 /**
 2  * Created by puff on 2016/1/1.
 3  */
 4 public class BaseInfo {
 5     private boolean shouldOpenDialog;
 6     private boolean shouldCloseDialog;
 7     private String dialogTitle;
 8     private String dialogMessage;
 9 
10     public boolean isShouldCloseDialog() {
11         return shouldCloseDialog;
12     }
13 
14     public void setShouldCloseDialog(boolean shouldCloseDialog) {
15         this.shouldCloseDialog = shouldCloseDialog;
16     }
17 
18     public boolean isShouldOpenDialog() {
19         return shouldOpenDialog;
20     }
21 
22     public void setShouldOpenDialog(boolean shouldOpenDialog) {
23         this.shouldOpenDialog = shouldOpenDialog;
24     }
25 
26     public String getDialogTitle() {
27         return dialogTitle;
28     }
29 
30     public void setDialogTitle(String dialogTitle) {
31         this.dialogTitle = dialogTitle;
32     }
33 
34     public String getDialogMessage() {
35         return dialogMessage;
36     }
37 
38     public void setDialogMessage(String dialogMessage) {
39         this.dialogMessage = dialogMessage;
40     }
41 }

  • ViewAdapter实现了IView接口,每次Activity调用refreshView时进行UI的从新渲染
 1 /**
 2  * Created by puff on 2016/1/1.
 3  */
 4 public abstract class ViewAdapter<T extends BaseInfo> implements IView<T> {
 5     /**
 6      * 根视图,用来进行view操做
 7      */
 8     private View mRootView;
 9     /**
10      * 状态集T
11      * View,Presenter经过T通讯,T更新进行refresh
12      */
13     private T mInfo;
14     /**
15      * 通用Dialog共用
16      */
17     private ProgressDialog mDialog;
18 
19     @Override
20     public void init(LayoutInflater inflater) {
21         mRootView = initViews(inflater);
22     }
23 
24     /**
25      * 实例化视图
26      *
27      * @param inflater
28      * @return 根视图
29      */
30     protected abstract View initViews(LayoutInflater inflater);
31 
32     @Override
33     public View getRootView() {
34         return mRootView;
35     }
36 
37     @Override
38     public void refreshView() {
39         if (mInfo == null) {
40             return;
41         }
42         if (mInfo.isShouldOpenDialog()) {
43             showDialog();
44             mInfo.setShouldOpenDialog(false);
45         }
46         if (mInfo.isShouldCloseDialog()) {
47             hideDialog();
48             mInfo.setShouldCloseDialog(false);
49         }
50     }
51 //其余操做
52

 

笔者经过这个结构,完成了一个简单的app,可以知足开发的基本需求。

PresenterAdapter只做业务处理,业务处理结果反映在状态集上,基本上都是针对数据操做的。而ViewAdapter则专一于经过状态集进行UI渲染。

特殊状况

包含AdapterView的页面复杂一些,由于大部分状况下咱们须要实现BaseAdapter进行AdapterView的数据填充。

BaseAdapter其实和咱们提到的ViewAdapter有类似之处,均是View的管理者,经过数据进行View的渲染。因此咱们也能够把BaseAdapter的实现类看成View层来处理。只不过状态集中须要有一个List<XX>来供BaseAdapter使用了。

 

尚存问题

这个思路仍是有不少问题

Fragment要如何处理?

Fragment包含了不少类Activity的功能,生命周期也很是复杂,在复杂应用中常常出现一个Activity包含多个Fragment的场景(Activity->ViewPager->Fragment,这种方式就很复杂),Fragment如何处理,笔者尚未想到很好的办法。

ActionBar,DecorView这种自然存在于Activity中的View如何处理?

ActionBar能够经过其余方式实现,DecorView没有想到什么好办法。

setListener放在P层,通常都须要经过R.id,这样就引用了View?

确实存在这个问题,也能够经过V层提供接口来处理,但会麻烦一些。

 

笔者水平有限,不少问题都没有解决,也仅是提供一种思路,望园友可以不吝赐教,共同进步~

相关文章
相关标签/搜索