Android MVP静态代理模式

热门标签

,

特别声明:文章多为网络转载,资源使用一般不提供任何帮助,特殊资源除外,如有侵权请联系!

连续写了好几天的 MVP 架构系列的文章,从一开始的 MVP 架构的介绍,到现在已经将 BaseMVP 框架的封装基本完成了,这段过程差不多花了一周的时间,对于我而言,无论在知识方面和写代码的能力方面,都有很大的提升。写博客,其实也是一个学习的过程,把自己学的总结一遍,我相信大部分人都像我一样,一个代码写完了,基本需求也搞定了,然后也就将代码扔到了一边,觉得当时会了的,可是,下次再遇到问题,发现又没有思路,没有方法去解决问题。

当然,另一方面,写博客可以发现自己的欠缺知识。比如,这阶段写的 BaseMVP 框架,用到的最多的就是反射的知识,我之前也写过一篇反射的文章,刚好直接开自己的博客回忆一下。所谓:温故而知新,可以为师矣。

那么,这篇文章就是给我们的 BaseMVP 框架做一个最后的总结与整改,这已经是第七篇连续的文章了,写着写着,都快可以形成短篇小说了,再不接近尾声的话,也没啥东西好写了。这几篇是紧密关联的,估计能看完的也比较少,大家都是忙于解决实际的问题,可能就我这总比较闲的大学生才会在这里长篇大论吧,但站在分享者的角度,我还是希望我的文章能有人看,能给大家带来帮助。

开篇写一点感想与总结做为铺垫,我比较喜欢这样做,如果喜欢看就纯粹当看看我的废话,不喜欢的就直接看问题和代码。我们基于上篇(Android MVP 架构MVP 之 BaseFragment 的封装)封装了 BaseFragment 基类,但此时又出现了代码冗余的情况,上篇末尾我就抛出了这个问题,那么在这篇中,我们究竟如何解决这个重复的代码情况,先来看看重复部分的代码:

BaseActivity 基类代码:

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 基类代码:

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;
    }
}

既然是做为框架而言,我们就应该去解决这个代码重复的问题。要想写好一个框架,这是我们必须要克服的一个问题,对比别人写的框架,多看看他们是如何解决重复性代码问题的方法,借鉴这些方法,引进我们的代码中,这就变成我们自己的东西了。对比 BaseActivity 和 BaseFragment 的代码,发现重复的代码如下:

重复处1:

Android MVP静态代理模式

重复处2:

Android MVP静态代理模式

对于重复的代码,我们一种最基本的是做法是抽取到父类中去,然后让这两个子类分别去继承它,这样可以做到代码的复用。但是,这里的抽取到父类的方法,其实并不合适在我们这个问题中去使用,因为 Java 是单继承的特性。

因为,我们的 BaseActivity 必须继承 Activity 才能启动,而 BaseFragment 又必须继承 Fragment 。所以这里不能瞎搞,无法用继承去搞的话,只能用接口的方法去试一试了,因为接口可以有多个。思来想去,这要这么搞呢,最终寻得良计,在这里用代理模式来处理这种情况,代理模式的代理方法必须是一个接口提供的,代码如下:

代理接口:IProxy 接口

package com.test.mvp.mvpdemo.mvp.v7.proxy;
 
public interface IProxy {
    void bindPresenter();
 
    void unbindPresenter();
}

代理接口中,提供了我们去绑定和解绑 Presenter 的抽象方法,具体的也就是上面重复的部分,我们需要新建一个接口实现类,用来统一代理重复的代码,代码如下:
IProxy 接口实现类: ProxyImpl 类

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;
    }
}

把重复的代码,全部抽取到 ProxyImpl 类中去处理,这样我们在 BaseActivity 和 BaseFragment 中就不用去写重复的代码了,不过在此,需要再新建两个代理的实现类,一个是 ProxyActivity 类,专门用来代理与 Activity 有关的代码,另一个就是 ProxyFragment 类,专门用来代理与 Fragment 有关的代码,代码如下:
新建 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 用构造函数的方式传给父类。

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

Android MVP静态代理模式

好了,你一定期待我们的 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 进行说明了,代码步骤都一样。

做一下最后的总结,这里运用了一个设计模式:代理模式,不懂的可以去查一查。当然,最重要的不是代码,而是解决问题的思路和方法。

 

标签:

未经允许不得转载:作者:SheaYang, 转载或复制请以 超链接形式 并注明出处 技术Dog|博客
原文地址:《Android MVP静态代理模式》 发布于2019-10-30

分享到:
赞(0)

评论 抢沙发

9 + 4 =


Android MVP静态代理模式

长按图片转发给朋友

Vieu4.0主题
专业打造轻量级个人企业风格博客主题!专注于前端开发,全站响应式布局自适应模板。

登录

忘记密码 ?

您也可以使用第三方帐号快捷登录

Q Q 登 录
微 博 登 录