您的位置:首页 > 移动开发 > Android开发

实现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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: