实现Android的MVP框架

对于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,Activity OnDestory 引用-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类型TestHttpResEvent

3.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



阅读更多
个人分类: Android
所属专栏: Android技术
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭