Use Android MVP (seven) static proxy mode

Disclaimer: This article is a blogger original article, follow the CC 4.0 BY-SA copyright agreement, reproduced, please attach the original source link and this statement.
This link: https://blog.csdn.net/smile_Running/article/details/95339274

Bloggers statement:

Please reprint this article at the beginning of additional links and author information, and marked as reserved. This article by the blogger  Whiskers Meow  original audience for support and advice.

This article first appeared in this    blogger : Whiskers Meow   |   blog home page : https://blog.csdn.net/smile_running

 

MVP architecture series:

Android MVP architecture (a) MVP architecture introduced with actual use

Android MVP architecture (two) BaseMVP MVP of the basic framework design

Memory leak analysis Android MVP MVP architecture (three) with dynamic proxies

Android MVP architecture (four) MVP generic configuration Model

Android MVP Architecture (e) a plurality of the MVP dependency injection Presenter

BaseFragment the Android MVP Architecture (six) of the MVP package

Android MVP architecture (seven) MVP of the proxy mode to eliminate duplication of code (End)

Source Address:

github Download: MVPDemo

csdn Download: MVPDemo

    Sequential Write for several days of MVP architecture series of articles outlining MVP architecture from the beginning, has now been encapsulated BaseMVP framework basically completed, this process took almost a week, for me, no matter in knowledge and ability to write code, has greatly improved. Blog, in fact, is a learning process, to sum up their own school again, I believe that most people are like me, a code is finished, and also get basic needs, then the code will be thrown aside, I feel that time will up, but, next time you encounter a problem, find and no ideas, no way to solve the problem.

    Of course, on the other hand, write a blog can be found in their lack of knowledge. For example, writing this stage of BaseMVP framework, we used the most is the reflection of knowledge, also wrote an article before I reflected, just open your own blog directly recall. The so-called: Reviewing the Old, can serve as a teacher.

    So, this article is to give our BaseMVP framework to make a final summary and rectification, this is the seventh consecutive articles published, and read, read, faster form of short stories, and do near the end, it did not what good things to write. It is a few closely related, is estimated to reading is relatively small, we are all busy solving practical problems that may take long-winded here on my students now total more leisure, but standing on the perspective of those who share, I hope my article will look at someone, it can bring help.

    Opening thoughts and write a little summary as bedding, I prefer to do this, if you like to see when I look at the sheer nonsense, do not like direct look at the issue and code. We based (Part package Android MVP architecture (six) BaseFragment the MVP of ) encapsulates BaseFragment base class, but this time they appeared in the case of code redundancy, at the end of Part I throw this question, then this we repeat exactly how to resolve this code, the first look at the code duplication section:

BaseActivity base class code:

public abstract class BaseActivity extends AppCompatActivity implements IBaseView {

    /**
     * 保存使用注解的 Presenter ,用于解绑
     */
    private List<BasePresenter> mInjectPresenters;

    protected abstract void initLayout(@Nullable Bundle savedInstanceState);

    protected abstract void initViews();

    protected abstract void initData();


    @SuppressWarnings("SameParameterValue")
    protected <T extends View> T $(@IdRes int viewId) {
        return findViewById(viewId);
    }

    @SuppressWarnings({"unchecked", "TryWithIdenticalCatches"})
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        initLayout(savedInstanceState);

        mInjectPresenters = new ArrayList<>();

        //获得已经申明的变量,包括私有的
        Field[] fields = this.getClass().getDeclaredFields();
        for (Field field : fields) {
            //获取变量上面的注解类型
            InjectPresenter injectPresenter = field.getAnnotation(InjectPresenter.class);
            if (injectPresenter != null) {
                try {
                    Class<? extends BasePresenter> type = (Class<? extends BasePresenter>) field.getType();
                    BasePresenter mInjectPresenter = type.newInstance();
                    mInjectPresenter.attach(this);
                    field.setAccessible(true);
                    field.set(this, mInjectPresenter);
                    mInjectPresenters.add(mInjectPresenter);
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (InstantiationException e) {
                    e.printStackTrace();
                }catch (ClassCastException e){
                    e.printStackTrace();
                    throw new RuntimeException("SubClass must extends Class:BasePresenter");
                }
            }
        }

        initViews();
        initData();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        /**
         * 解绑,避免内存泄漏
         */
        for (BasePresenter presenter : mInjectPresenters) {
            presenter.detach();
        }
        mInjectPresenters.clear();
        mInjectPresenters = null;
    }

    @Override
    public Context getContext() {
        return this;
    }
}

BaseFragment base class code:

public abstract class BaseFragment extends Fragment implements IBaseView {

    private List<BasePresenter> mInjectPresenters;

    private View mLayoutView;

    protected abstract @LayoutRes int setLayout();

    protected abstract void initViews(@Nullable Bundle savedInstanceState);

    protected abstract void initData();

    @SuppressWarnings("ConstantConditions")
    protected <T extends View> T $(@IdRes int viewId) {
        return this.getView().findViewById(viewId);
    }

    @SuppressWarnings({"unchecked", "TryWithIdenticalCatches"})
    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(setLayout(), container, false);

        mInjectPresenters = new ArrayList<>();

        //获得已经申明的变量,包括私有的
        Field[] fields = this.getClass().getDeclaredFields();
        for (Field field : fields) {
            //获取变量上面的注解类型
            InjectPresenter injectPresenter = field.getAnnotation(InjectPresenter.class);
            if (injectPresenter != null) {
                try {
                    Class<? extends BasePresenter> type = (Class<? extends BasePresenter>) field.getType();
                    BasePresenter mInjectPresenter = type.newInstance();
                    //绑定
                    mInjectPresenter.attach(this);
                    field.setAccessible(true);
                    field.set(this, mInjectPresenter);
                    mInjectPresenters.add(mInjectPresenter);
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (java.lang.InstantiationException e) {
                    e.printStackTrace();
                } catch (ClassCastException e) {
                    e.printStackTrace();
                    throw new RuntimeException("SubClass must extends Class:BasePresenter");
                }
            }
        }
        return view;
    }

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        initViews(savedInstanceState);
        initData();
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        for (BasePresenter presenter : mInjectPresenters) {
            presenter.detach();
        }
        mInjectPresenters.clear();
        mInjectPresenters = null;
    }
}

     Since it is concerned as a framework, we should repeat the code to solve this problem. To write a framework, which is a problem we have to overcome, comparative framework written by someone else, how they see more method to solve the problem of repetitive codes, learn from these methods, the introduction of our code, this change with our own things. Comparative Code BaseActivity and BaseFragment found duplicate code as follows:
duplicate at 1:

 Repeat at 2:

    For repeat code it is our most basic approach is to extract parent class to go, and then let the two sub-categories are to inherit it, this can be done code reuse. But here's the method to extract parent class, is not appropriate to use in our problem, because Java is a single inheritance of characteristics .

    Because our BaseActivity must inherit Activity to start, but it must inherit BaseFragment Fragment. So there can not be messing around, unable to engage with the inheritance, you can only use the interface methods to try, because you can have multiple interfaces. Thought to want to, so this should do it, and ultimately find a good count, where use proxy mode to handle this case, the proxy method must be a proxy mode interface provides the following code:

Agent Interface: IProxy Interface

package com.test.mvp.mvpdemo.mvp.v7.proxy;

public interface IProxy {
    void bindPresenter();

    void unbindPresenter();
}

    Agent interface, provides an abstract method to bind us to the reconciliation tied Presenter, the specific part that is repeated above, we need to create a class interface for unified agent repetitive code, the code is as follows:

IProxy interface classes: ProxyImpl class

package com.test.mvp.mvpdemo.mvp.v7.proxy;

import com.test.mvp.mvpdemo.mvp.v7.basemvp.BasePresenter;
import com.test.mvp.mvpdemo.mvp.v7.basemvp.IBaseView;
import com.test.mvp.mvpdemo.mvp.v7.inject.InjectPresenter;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;

public class ProxyImpl implements IProxy {

    private IBaseView mView;
    private List<BasePresenter> mInjectPresenters;

    public ProxyImpl(IBaseView view) {
        this.mView = view;
        mInjectPresenters = new ArrayList<>();
    }

    @SuppressWarnings({"unchecked", "TryWithIdenticalCatches"})
    @Override
    public void bindPresenter() {
        //获得已经申明的变量,包括私有的
        Field[] fields = mView.getClass().getDeclaredFields();
        for (Field field : fields) {
            //获取变量上面的注解类型
            InjectPresenter injectPresenter = field.getAnnotation(InjectPresenter.class);
            if (injectPresenter != null) {
                try {
                    Class<? extends BasePresenter> type = (Class<? extends BasePresenter>) field.getType();
                    BasePresenter mInjectPresenter = type.newInstance();
                    mInjectPresenter.attach(mView);
                    field.setAccessible(true);
                    field.set(mView, mInjectPresenter);
                    mInjectPresenters.add(mInjectPresenter);
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (InstantiationException e) {
                    e.printStackTrace();
                } catch (ClassCastException e) {
                    e.printStackTrace();
                    throw new RuntimeException("SubClass must extends Class:BasePresenter");
                }
            }
        }
    }

    @Override
    public void unbindPresenter() {
        /**
         * 解绑,避免内存泄漏
         */
        for (BasePresenter presenter : mInjectPresenters) {
            presenter.detach();
        }
        mInjectPresenters.clear();
        mInjectPresenters = null;
    }
}

     The duplicate code, all drawn to  ProxyImpl class to deal with, so we will not have to write duplicate code in BaseActivity and BaseFragment in, but in this case, two agents need to create a new implementation class, a class is ProxyActivity, special Activity for codes associated with the agent, is another class ProxyFragment specifically related to Fragment proxy code, the code is as follows:

新建 ProxyActivity 类:

package com.test.mvp.mvpdemo.mvp.v7.proxy;

import com.test.mvp.mvpdemo.mvp.v7.basemvp.IBaseView;

public class ProxyActivity<V extends IBaseView> extends ProxyImpl {
    public ProxyActivity(V view) {
        super(view);
    }
}

新建 ProxyFragment 类:

package com.test.mvp.mvpdemo.mvp.v7.proxy;

import com.test.mvp.mvpdemo.mvp.v7.basemvp.IBaseView;

public class ProxyFragment<V extends IBaseView> extends ProxyImpl {
    public ProxyFragment(V view) {
        super(view);
    }
}

    这里两个代理类暂时没上面代码,因为还没上面业务逻辑要处理。不过,必须要传入一个泛型的 IBaseView 对象,这里的原因就是我们的 ProxyImpl 类中的 presenter 调用 attach() 方法去绑定 View 时,这个 View 是继承 IBaseView 的,所以这必须要一个参数给它,通过继承 ProxyImpl 类将这个 view 用构造函数的方式传给父类。

    到这里,就好了。总得来说,这里就新建了几个代理类,我们来看一下项目包发生的变化吧:

    好了,你一定期待我们的 BaseActivity 和 BaseFragment 中的代码到底少了多少,或者你肯定想知道如何调用代理类,下面来看看吧:

修改 BaseActivity 基类:

public abstract class BaseActivity extends AppCompatActivity implements IBaseView {

    private ProxyActivity mProxyActivity;

    protected abstract void initLayout(@Nullable Bundle savedInstanceState);

    protected abstract void initViews();

    protected abstract void initData();


    @SuppressWarnings("SameParameterValue")
    protected <T extends View> T $(@IdRes int viewId) {
        return findViewById(viewId);
    }

    @SuppressWarnings({"unchecked", "TryWithIdenticalCatches"})
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        initLayout(savedInstanceState);

        mProxyActivity = createProxyActivity();
        mProxyActivity.bindPresenter();

        initViews();
        initData();
    }

    @SuppressWarnings("unchecked")
    private ProxyActivity createProxyActivity() {
        if (mProxyActivity == null) {
            return new ProxyActivity(this);
        }
        return mProxyActivity;
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mProxyActivity.unbindPresenter();
    }

    @Override
    public Context getContext() {
        return this;
    }
}

    调用很简单,首先实例化 ProxyActivity 对象,然后调用它父类的 bind 和 unbind 方法就可以了。很明显,把那一坨长长的代码抽掉了以后,BaseActivity 显得异常清爽,瞬间瘦身成功。这里我就不对 BaseFragment 进行说明了,代码步骤都一样。

    做一下最后的总结,这里运用了一个设计模式:代理模式,不懂的可以去查一查。这篇文章的结束,也代表这本系列文章的结束,因为我们 BaseMVP 框架已经可以上手使用了,我们从第一篇的 MVP 的使用到这篇的 BaseMVP 封装过程中发现的一些问题和解决方法都差不多仔仔细细的写清楚,写明白了。当然,最重要的不是代码,而是解决问题的思路和方法。

    如果你有足够的学习热情,你可以从第一篇到最后一篇依次看下来,我相信你收获的一定不少。对了,这里肯定有人需要源代码,我会发到 csdn 和 github 上,喜欢的可以点个赞,如果有错的,欢迎纠错。

Guess you like

Origin blog.csdn.net/smile_Running/article/details/95339274