安卓框架搭建(四)mvp架构及封装

前言: 

从入行安卓开发 绝大部分人都从mvc开始的,当然也有后起之秀直接从 mvp开始入手的  , 到目前随着技术的发展,现在也逐渐开始流行mvvm架构,但是相对来说,mvp还是主导潮流,下面我就将从简单到封装,逐步架构mvp模式

如果有不了解mvp基本使用的,可以去百度搜一搜基本用法, 这里只讲一下简单的封装, 方便使用

mvp模式在使用过程中一个最主要的问题就是容易造成内存泄露,这个是mvp的普遍现象,所以在这里先将mvp内存泄露的基类封装

BasePresenter的封装

view层的引用实际上就相当于activity的视图
为了防止内存泄漏 在创建view层的引用的时候 , 通常情况是直接传递要绑定的view 然后在onDetachView的时候 将view 置空
这里我们采用弱引用的方式来构造视图层 , 如果有不了解弱引用的 可以去查看一下四种引用的用法,弱引用是经常用到的比如解决网络请求handler造成的内存溢出等,这里不做详细讲解
在继承basePresenter的时候传递一个view , 在创建presenter的时候 进行绑定, 当解绑presenter的时候讲view解绑

泛型V为与presenter相关的view。BasePresenter中持有一个view的弱引用。

public class BasePresenter { 

    protected WeakReference mTWeakReference;
    
    //进行绑定
    public void onAttachView(V view) {
        mTWeakReference = new WeakReference(view);
    }

    //进行解绑
    public void onDetachView() {
        if (mTWeakReference != null)
            mTWeakReference.clear();
    }
    protected V getView() {
        return mTWeakReference.get();
    }
    public boolean isViewAttached() {
        return mTWeakReference != null && mTWeakReference.get() != null;
    }

}

BaseView的封装

view层的封装就比较简单的, 主要考虑一下工程中有哪些公共的部分 , 比如请求网络时候的加载动画, 请求网络失败时候的提醒等等

public interface BaseView {
    //开启加载动画
    void showLoading();

    //隐藏加载动画
    void hideLoading(boolean b);

    //错误信息
    void onError(V result);
}
public interface BaseModel {
    void loadDate(onCallBackListener callBackListener);
}

loadData采用的是无参的形式 ,接口回调的方式来获取数据的 ,而不是采用  void loadDate(List data); 这种返回值的方式

 原因是 当方法执行的时候 ,一旦数据没有返回,方法就会停留在这一直等待方法返回数据
 这样当网络延迟或者网络突然中断时,整个应用就会停留在这里,造成ui卡顿 甚至anr异常
利用接口回调的方式来获取数据 , 用来监听数据的返回情况 这样当请求网络的时候 方法就不会一直等待返回值而造成ui卡顿 , 当监听有数据之后再经过回调将数据发送过去

回调数据需要的接口

/**
 * Created by yc on 2018/7/26.
 * //定义一个公共的接口来接收返回的数据 (范型传什么 回调中就接什么数据即可)
 */

public interface onCallBackListener {
//因为成功的回调中犹豫每个请求的数据都是不同的所以用范型来定义
    void onSuccess(T t);
//而失败只会有一种情况 所以这里直接用字符串的方式来接收

    void onFailed(String e);

}

基础类就已经完成了 ,下面介绍如何使用

1.创建model层

basemodel层中抽取出公共的部分比如每个界面都有同一个类型的请求的时候 , 只要即成basemodel 即可 不用在写方法传递回调,如果有其他数据需要请求,在单独定义即可

/**
 * Created by yc on 2018/7/25.
 */

public interface HomeModel extends BaseModel {

    void loadDate1(onCallBackListener callBackListener);
}
public class HomeModelImpl implements HomeModel {
   
    public void loadDate1(onCallBackListener callBackListener) {
        List homeBeanList = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            homeBeanList.add(new HomeBean("名字 :" + i));
        }
        //通过回调将数据返回给 model层
        callBackListener.onSuccess(homeBeanList);
    }
}

这里将数据的操作单独定义出来一个类来实现数据模型的处理,这样觉得麻烦的也可以直接在同一个数据模型中处理

2.V层的创建

与basemodel类似不多做介绍

/**
 * Created by yc on 2018/7/25.
 */

public interface IHomeView extends BaseView {
    //显示recyview中的数据,(使用回调的方式返回数据,不用返回值返回的原因是因为防止在请求数据的时候方法在等待返回值而是ui变的卡顿)
    void showhome(ApiResult apiResult);
}

3.数据类

这里用的是聚合数据的数据,如果凑巧你的服务器端的返回数据与此一致那么不用多做修改,如果不一致,那么可将你的数据传递到范型中,然后重新解析并进行其他的操作

public class ApiResult {
    private int error_code;
    private String reason;
    private T result;

    public int getError_code() {
        return error_code;
    }

    public void setError_code(int error_code) {
        this.error_code = error_code;
    }

    public String getReason() {
        return reason;
    }

    public void setReason(String reason) {
        this.reason = reason;
    }

    public T getResult() {
        return result;
    }

    public void setResult(T result) {
        this.result = result;
    }

    @Override
    public String toString() {
        return "ApiResult{" +
                "error_code=" + error_code +
                ", reason='" + reason + '\'' +
                ", result=" + result +
                '}';
    }
}

4. P层的处理

 

/**
 * Created by yc on 2018/7/25.
 */
//1.即成basePresenter 获取传递过来的view对象
public class HomePresenter extends BasePresenter {

    //2。model层的引用 (model 可以直接new创建)
    HomeModel mHomeModel = new HomeModelImpl();

    //3.构造方法 (因为 view 相当于activity 不能直接new创建 ,所以通过构造方法将view视图层传递过来 ,此view继承自 IHomeView)
    public HomePresenter() {
    }

    //4执行获取数据的方法
    public void getHomeData() {
        if (mTWeakReference.get() != null) {
            mTWeakReference.get().showLoading();
            if (mHomeModel != null) {
                mHomeModel.loadDate(new onCallBackListener() {
                    @Override
                    public void onSuccess(ApiResult apiResult) {
                        mTWeakReference.get().showhome(apiResult);
                    }

                    @Override
                    public void onFailed(String e) {
                        mTWeakReference.get().onError(e);
                    }
                });
            }
        }
    }
}

5.数据处理的逻辑都已经完成,下面看看页面都有哪些逻辑

public class HomeFragment extends BaseFragment> implements IHomeView {
    private static HomeFragment sHomeFragment;

    public static HomeFragment newInstance(String param1) {
        sHomeFragment = new HomeFragment();
        Bundle args = new Bundle();
        args.putString("agrs1", param1);
        sHomeFragment.setArguments(args);
        return sHomeFragment;
    }

    public HomeFragment() {

    }


    @Override
    protected HomePresenter createPresenter() {
        return new HomePresenter<>();
    }

    @Override
    protected int initLayoutInflater() {
        return R.layout.home_fragment;
    }

    @Override
    public void initView() {

    }

    @Override
    public void initData() {
        basePresenter.getHomeData();
    }

    @Override
    public void showhome(ApiResult apiResult) {
        Toast.makeText(getActivity(), apiResult.toString(), Toast.LENGTH_SHORT).show();
    }

    @Override
    public void showLoading() {

    }

    @Override
    public void hideLoading(boolean b) {

    }

    @Override
    public void onError(Object result) {

    }
}

7.BaseFragment的封装优化

在basefragment传入相应的view 和 presenter 这样在子类继承父类的时候不用在重复的去写 绑定view 和移除view 的相关操作

使代码更加简洁

public abstract class BaseFragment> extends Fragment {
    public String TAG = getClass().getSimpleName().toString();
    private Unbinder mUnbinder;
    //表示层的引用
    protected P basePresenter;

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(initLayoutInflater(), container, false);
        mUnbinder = ButterKnife.bind(this, view);
        //将子类创建的presenter 赋值给基类表示层
        basePresenter = createPresenter();
        if (basePresenter != null)
            //绑定
            basePresenter.onAttachView((V) this);
        initView();
        initData();
        return view;
    }


    protected abstract P createPresenter();

    protected abstract int initLayoutInflater(); //初始化布局

    public abstract void initView();

    public abstract void initData();

    private P getPresenter() {
        return basePresenter;
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        if (mUnbinder != null)
            mUnbinder.unbind();
        if (basePresenter != null)
            //解绑
            basePresenter.onDetachView();
        Toast.makeText(getActivity(), "父类fragment_base销毁", Toast.LENGTH_SHORT).show();
    }
}

 

从上面代码中可以看出。 首页继承BaseFragment后,将视图view层传递过去之后 , 实现view的方法

在createPresenter方法中返回HomePresenter

 @Override
    protected HomePresenter createPresenter() {
        return new HomePresenter<>();
    }

 在需要调用数据的地方调用   basePresenter.getHomeData();  

    @Override
    public void initData() {
        basePresenter.getHomeData();
    }

在showhome 方法中接收返回回来的数据即可,整体看起来比mvc模式要简洁很多,也比较容易后期维护与管理


好了以上就是, 安卓框架搭建(四)mvp架构及封装,的所有内容

如有不了解的 可以去github下载源码 本章节内容为分支4

github源码地址 分支4

或 加入安卓开发交流群:安卓帮595856941

相关链接:

下一篇:

安卓框架搭建(五)增加底部导航栏

 

 

 

 

你可能感兴趣的:(安卓架构)