实现Android的MVP框架
2016-06-25 16:11
417 查看
对于Android到底使用MVC,MVVM还是MVP相信大家已经争论已久了。其实争论的由来个人认为对于Activity的存在,这个角色似乎介于View和Controller之间。难免内部会耦合大量逻辑。其实这也和Android的设计思路有关,Android每个活动片段被设计成一个Context,即一个上下文,一个场景,一次交互。这是一个很抽象的概念,对于Context来说,Android四大组件都与其紧密相连,Activity和Service直接继承于他(包括Application),ContentProvider、BroadcastReceiver则接受Context实现类的调用。对于Activity等组件来说Context像是身份证,很多活动都要作为参数传进去,以识别调用者的身份,Context中记载着每个场景太多的状态信息。对于Android系统框架来说,Context像是一部法典,是"社会"的基本法,活动都要按照Context的规定进行。单从Context来说,它更适合存放逻辑。对于线程来说,Context是ActivityThread即主线程经过的生命线,就像主线程的“上下文了”。对于Activity来说,虽然他是Context的实现类,Activity继承于ContextThemeWrapper,包含了大量与UI相关的操作,这就是问题由来的原因。Activity太重要了,包含了太多的东西,比如程序的驱动者,Activity的生命周期,按键的监听,都是逻辑运行的起点。1.设计思路:MVP中,Activity将被封装成View,仅暴露get或set接口,当然必要的回调是不可少的。1.1)首先,考虑View和Presenter的关系,很明显是多对一的关系,一个Presenter可以对应多个View,考虑到Activity中的Window是View的容器,就把一个Activity当作一个View的集合或管理单位(描述可能有些不合适)。即一个Presenter对应多个Activity。1.2)其次,既然选择了多对一的关系,Presenter就应该交由框架管理,和Activity相同,Presenter和Activity的用户实现不应该承担管理Presenter生命周期的角色,Presenter实例应该存储在框架中的一个集合内,和Activity栈类似。框架内部使用类似智能指针的方式管理Presenter实例,Activity Oncreate即引用+1,ActivityOnDestory 引用-1,引用==0即启动Presenter的销毁流程。1.3)然后,既然一个Presenter管理着多个Activity,那么Presenter自然需要知道Activity的切换,所以要设计相应的监听。此外,为了Presenter能接收到Activity的生命周期,Presenter也需要设计出相应的监听。2.尝试实现:2.1)Presenter抽象类实现2.1.1)Presenter调用接口
public interface IPresenterCallBack { public void OnPresentInited(Context context); public void OnPresentSeted(Context context); public Context getContext(); public Activity getActivityRaw(); public IActivity getActivityInter(); public void DestoryPresent(); }从字面上也能猜出大概的意思了2.1.2) Presenter
public abstract class Presenter implements IPresenterCallBack{ //当前栈顶的Presenter 即当前栈顶Activity对应的Presenter private static Presenter curPresenter; //所有的Presenter private static WeakHashMap<Class<? extends Presenter>,Presenter> presents = new WeakHashMap<Class<? extends Presenter>,Presenter>();; //当前Presenter对应的Context(栈顶Activity)的弱引用 private WeakReference<? extends Context> curContextRef; //当前Presenter对应的所有Context private List<Context> contextList; public Presenter() { contextList = new ArrayList<Context>(); curPresenter = this; InjectAsycTask.getInstance().inject(this); HttpInjectUtil.getInstance().inject(this); } //分析注解绑定Presenter public static Presenter regist(Context context){ Class<?> type = context.getClass(); InjectPresenter inject = type.getAnnotation(InjectPresenter.class); if (inject == null) { try { throw new ClassNotFoundException(); } catch (ClassNotFoundException e) { e.printStackTrace(); } } Class<? extends Presenter> clazz = inject.value(); Presenter presenter = getPresent(clazz); if (presenter == null){ try { presenter = clazz.newInstance(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } putPresent(presenter); } presenter.addContext(context); return presenter; } //解绑 public static void unregist(Context context){ Presenter presenter = ((IContext)context).getPresent(); presenter.removeContext(context); if (presenter.getContexts().size() == 0) destoryPresenter(presenter); } @Override public void OnPresentSeted(Context context) { Context preContext = null; if (curContextRef !=null) preContext = curContextRef.get(); this.curContextRef = new WeakReference<Context>(context); if (getCurPresenter() != ((IContext)context).getPresent()) setCurPresnter(((IContext)context).getPresent()); if (preContext == null){ OnPresentInited(context); return; } ContextChangeEvent event = new ContextChangeEvent(); if (preContext instanceof Activity){ if (context instanceof Activity) event.setAction(ContextChangeEvent.ACTIVITY_ACTIVITY); else if (preContext instanceof Service) event.setAction(ContextChangeEvent.ACTIVITY_SERVICE); }else if (preContext instanceof Service){ if (context instanceof Activity) event.setAction(ContextChangeEvent.SERVICE_ACTIVITY); else if (preContext instanceof Service) event.setAction(ContextChangeEvent.SERVICE_SERVICE); } event.setContext(context); onContextChanged(event); } //销毁Presenter的回调,子类可以重写 @Override public void DestoryPresent() { HttpInjectUtil.getInstance().remove(this); InjectAsycTask.getInstance().remove(this); } protected abstract void onContextChanged(ContextChangeEvent event); @Override public Context getContext() { return curContextRef.get(); } public Activity getActivityRaw(){ return (Activity) getContext(); } public IActivity getActivityInter(){ return (IActivity) getActivityRaw(); } public Service getServiceRaw(){ return (Service) getContext(); } protected <T extends View> T getView(int ViewId){ return getActivityInter().getView(ViewId); } protected void startActivity(Intent intent){ //OnActivityChangeBefore(); getActivityRaw().startActivity(intent); } public static Presenter getCurPresenter() { return curPresenter; } public static void setCurPresnter(Presenter presnter){ curPresenter = presnter; } public static Presenter getPresenter(Class<? extends Presenter> key){ return presents.get(key); } private static void destoryPresenter(Presenter presenter){ presenter.DestoryPresent(); presents.remove(presenter.getClass()); } public static Presenter getPresent(Class clazz){ return presents.get(clazz); } public static void putPresent(Presenter presenter){ presents.put(presenter.getClass(),presenter); } public void addContext(Context context){ contextList.add(context); } public void removeContext(Context context){ contextList.remove(context); } public List<Context> getContexts(){ return contextList; }和Intent的setClass类似,Presenter框架也是通过相应的类型找到Presenter实例的,为了和自己的框架相融,设计成了注解绑定,类似Xutils的@ContentView,抽象出两个方法,OnPresenterInit和OnContextChange是必须要实现的。2.2)这样一来,为了配合Presenter,Activity也必须重写了。2.2.1)IActivity接口,封装了Activity生命周期监听方法,以及getView(findviewbyid的封装),和一些简单的set接口。
<span style="font-size:10px;">public interface IActivity { public <T extends View> T getView(int ViewId); public void setText(int id,String str); public void setImg(int id, Bitmap bitmap); public void setOnCreateListener(ActivityOnCreatedListener listener); public void setOnDestroyListener(ActivityOnDestoryListener listener); public void setOnStartListener(ActivityOnStartListener listener); public void setOnRestartListener(ActivityOnRestartListener listener); public void setOnResumeListener(ActivityOnResumeListener listener); public void setOnStopListener(ActivityOnStopListener listener); public void setOnPauseListener(ActivityOnPauseListener listener); }</span>2.2.2)IContext接口
<span style="font-size:10px;">public interface IContext<T extends Presenter> { public T getPresent(); }</span>2.3)BaseActivity实现
<span style="font-size:10px;">public abstract class BaseAppCompactActivity<P extends Presenter> extends AppCompatActivity implements IActivity,IContext<P>{ //通过getView管理的View集合 private SparseArray<View> mViews; //生命周期的监听集合 private Map<Class,Object> listeners; //对应的Presenter的引用 private WeakReference<IPresenterCallBack> callbackRef; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mViews = new SparseArray<View>(); listeners = new HashMap<Class,Object>(); setPresent(); //注解框架 ViewInjectAll.getInstance().inject(this); ActivityOnCreatedListener listener = (ActivityOnCreatedListener) listeners.get(ActivityOnCreatedListener.class); if (listener!=null) listener.ActivityOnCreated(savedInstanceState,this); } private void setPresent(){ callbackRef = new WeakReference<IPresenterCallBack>((IPresenterCallBack) Presenter.regist(this)); setActivity(); } private void setActivity(){ callbackRef.get().OnPresentSeted(this); } @Override protected void onStart() { super.onStart(); if (callbackRef.get().getActivityRaw() != this) setActivity(); ActivityOnStartListener listener = (ActivityOnStartListener) listeners.get(ActivityOnStartListener.class); if (listener != null) listener.ActivityOnStart(this); } @Override protected void onRestart() { super.onRestart(); ActivityOnRestartListener listener = (ActivityOnRestartListener) listeners.get(ActivityOnRestartListener.class); if (listener != null) listener.ActivityOnRestart(this); } @Override protected void onResume() { super.onResume(); ActivityOnResumeListener listener = (ActivityOnResumeListener) listeners.get(ActivityOnResumeListener.class); if (listener != null) listener.ActivityOnResume(this); } @Override protected void onPause() { super.onPause(); ActivityOnPauseListener listener = (ActivityOnPauseListener) listeners.get(ActivityOnPauseListener.class); if (listener != null) listener.ActivityOnPause(this); } @Override protected void onStop() { super.onStop(); ActivityOnStopListener listener = (ActivityOnStopListener) listeners.get(ActivityOnStopListener.class); if (listener != null) listener.ActivityOnStop(this); } @Override protected void onDestroy() { super.onDestroy(); InjectAsycTask.getInstance().remove(this); ActivityOnDestoryListener listener = (ActivityOnDestoryListener) listeners.get(ActivityOnDestoryListener.class); if (listener!=null) listener.ActivityOnDestory(this); Presenter.unregist(this); } public <T extends View> T getView(int ViewId) { T view = (T) mViews.get(ViewId); if (view == null) { view = (T)findViewById(ViewId); mViews.put(ViewId, view); } return view; } public void setText(int id,String str){ TextView view = getView(id); view.setText(str); } public void setImg(int id, Bitmap bitmap){ ImageView imageView = getView(id); imageView.setImageBitmap(bitmap); } public void setOnCreateListener(ActivityOnCreatedListener listener){ listeners.put(ActivityOnCreatedListener.class,listener); } public void setOnDestroyListener(ActivityOnDestoryListener listener){ listeners.put(ActivityOnDestoryListener.class,listener); } public void setOnStartListener(ActivityOnStartListener listener){ listeners.put(ActivityOnStartListener.class,listener); } public void setOnRestartListener(ActivityOnRestartListener listener){ listeners.put(ActivityOnRestartListener.class,listener); } public void setOnResumeListener(ActivityOnResumeListener listener){ listeners.put(ActivityOnResumeListener.class,listener); } public void setOnStopListener(ActivityOnStopListener listener){ listeners.put(ActivityOnStopListener.class,listener); } public void setOnPauseListener(ActivityOnPauseListener listener){ listeners.put(ActivityOnPauseListener.class,listener); } @Override public P getPresent() { return (P) callbackRef.get(); } }</span>3.应用演示3.1)应用包结构个人不喜欢写模块间的接口,这里利用自己框架实现的EventPoster(类似EventBus)来接耦,这里的“接口”实际上变成了Event类型TestHttpResEvent3.1)Activity
@ContentView(R.layout.activity_test) @InjectPresenter(TestPresenter.class) public class TestActivity extends BaseAppCompactActivity<TestPresenter> { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); } public void Show(String str){ String txt = getPresent().dealStr(str); setText(R.id.TestTextView,txt); } }可以发现,这里使用注解绑定了对应的Presenter,其后Presenter的生命周期就开始受框架管理。Activity只负责
对View操作。
3.2)Presenter
<span style="font-size:10px;">public class TestPresenter extends Presenter{ @Override protected void onContextChanged(ContextChangeEvent event) { } @Override public void OnPresentInited(Context context) { EventPoster.Regist(this); getActivityInter().setOnCreateListener(new ActivityOnCreatedListener() { @Override public void ActivityOnCreated(Bundle savedInstanceState, Activity activity) { TestModel model = new TestModel(); model.doHttp(); } }); } @InjectEvent(type = EventThreadType.MainThread) public void OnHttpModelRes(TestHttpResEvent event){ TestActivity ac = (TestActivity) getActivityRaw(); ac.Show(event.getRes().getStr()); } public String dealStr(String str){ return str+"end!"; } @Override public void DestoryPresent() { super.DestoryPresent(); EventPoster.Unregist(this); } }</span><span style="font-size:18px;"> </span>presenter中监听了Activity的Oncreate事件,并调用了Model层获取http数据,Model层异步获取数据之后
对Presenter发送Event,即在主线程回调,在回调里调用了View层的Show函数,Show函数又调用了Presenter的
字符串处理函数。
整个程序逻辑清晰,把Activity内的逻辑几乎抽了个干干净净。个人觉得这样看起来比较ok一点,当然这仅仅代表
个人观点,如有错误欢迎大家讨论。
最后,附上源码,已经集成在我的小框架里了欢迎下载。GitHub
相关文章推荐
- RecyclerView之使用ItemTouchHelper和ItemTouchHelper.Callback实现条目拖拽排序
- 4.0、Android Studio配置你的构建
- 4.0、Android Studio配置你的构建
- Android 绘制N阶Bezier曲线
- Android GridView 的使用
- Android的Fragment中onActivityResult不被调用的最终解决方案
- Android传感器完全解析
- android 通知(1)
- Android中获取手机通信录中的联系人
- unable to start the daemon process (安卓项目不能运行报错)
- Android中的数据存储(一)----- 文件存储
- Android4编程入门经典 - 学习摘录笔记 - 1
- android json解析
- android 四大组件之Service(7) 结合通知
- Ubuntu编译vlc-android
- Android深度系列—Activity四种启动方式与栈原理
- 编译安卓源码以及下载Android内核
- android Bitmap用法总结
- Anroid gson解析
- ROS实时采集Android的图像和IMU数据