在android项目开发中,随着功能不断迭代,代码量一般也会随之不断增长,维护成本愈来愈高。android
做为开发者,笔者常常会被杂乱的逻辑搞的焦头烂额,不由思考:什么样的结构可以简化开发,同时又能下降维护成本?git
当下开发中比较推崇的是三层架构,典型表明便是MVP。笔者在此将最近对MVP的理解与心得与你们分享一下。github
一直以来,笔者对android中MVP模式的理解并无很透彻,最近看了kymjs的文章《用MVP架构开发Android应用》,有一种醍醐灌顶的感受,特在此感谢做者。做者的MVP框架也放到了Github上——TheMVP,感兴趣的朋友能够多加关注。架构
就我的的理解,目前对MVP的分歧,主要在于Activity的归属问题上。大部分人认为Activity属于V层,但也有部分人认为Activity属于P层。app
以登录页面为例,两个Edittext分别获取帐号和密码,一个Button用于登录。Activity首先setContentView,随后添加Button的点击监听,onClick中获取帐号和密码进行请求,一鼓作气。流程中setContentView,对Button进行监听,均须要对ui元素直接操做。如果复杂页面,则ui元素的直接操做将会更多,Activity做为V层有自然的优点。框架
Activity中提供了很是多的回调方法,同时做为Context的实现类,各类Manager都可经过Activity来调用。能够说,咱们能想到的绝大部分逻辑操做都可以在Activity来完成,Activity也有做为P层的潜质。ide
既然Activity做为V层、P层均有必定道理,咱们又应该如何理解Activity呢?布局
Activity是上帝类,咱们在Activity中作任何事情都是能够的。ui
试想一下,在一个动态布局的页面中,咱们可能不须要xml来写布局,全部控件都是代码生成。各类事件也均有Activity来处理,其中也包括了file操做等。一个Activity将MVP的操做都作了,是否是很万能?this
仅从笔者的开发经验来看,对MV*模式的使用并很少,大部分状况下采用Activity/Fragment+Model层。
当咱们开发一个逻辑并不特别复杂的app时,只要抽象合理,代码应当不难维护,也没必要借助MV*模式了。
但随着PM的奇思妙想愈来愈多,项目越作越大,一个Activity可能几千行,各类逻辑交织,显得异常复杂。这时候咱们就能够考虑经过MV*来拯救咱们了!
换句话说,采用MV*模式自己也是一种无奈。业务过于复杂,只能经过拆分层次,将复杂的问题分而治之。
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进行渲染。
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 }
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 }
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层提供接口来处理,但会麻烦一些。
笔者水平有限,不少问题都没有解决,也仅是提供一种思路,望园友可以不吝赐教,共同进步~