Android MVP框架设计(1)

1.接口设计

V:定义数据处理规范的接口
public interface IHandler<T> {
    void onBefore();      //加载前
    void setData(T data); //View层调用
    void onSuccess(boolean isHaveData);  //加载成功
    void onFailure(int code, String msg);//加载失败
}
 :我们希望Activity或Fragment实现该接口来处理返回的数据
public interface IView<T> {
    void bindView(View contentView);
    void bindData(T data);
}
P:建立M层和V层之间的联系
public interface IPresent<T> {
    void setModel(IModel<T> model);
    void setContent(IView<T> adapter);
    void build();
    void refresh();
}
M:发起网络请求
public interface IModel<T> {
    void refresh(IHandler<T> handler);//入口函数中持有IHandler的实例用于处理响应结果
}

2.核心类

public class CommonPresent<T> implements IPresent<T>, IHandler<T> {
    protected View        mContentView;//指向目标内容视图,一般为Activity或Fragment中的根视图
    protected IModel      mModel;
    protected IView<T> mIview ;

    public CommonPresent(View view) {
        mContentView = view;
    }

    public CommonPresent(Context context, int layoutResId) {
        this(View.inflate(context, layoutResId, null));
    }

    @Override
    public void setModel(IModel<T> model) {
        mModel = model;
    }

    @Override
    public void setContent(IView<T> iview) {
        mIview = iview;
    }

    @Override
    public void build() {
        if (mModel == null) {
            throw new RuntimeException("Model is null, you need implement setModel(...)");
        }
        if (mIview != null) {
            mIview.bindView(mContentView);
        }
    }

    @Override
    public void refresh() {
        //此处为关键代码,用IModel代理CommonPresent的refresh()函数,
        //并用当前CommonPresent对象作为IModel的请求的回调处理对象
        mModel.refresh(this);
    }

    public View getContentView() {
        return mContentView;
    }

    @Override
    public void onBefore() {
    }

    @Override
    public void onSuccess(boolean isHaveData) {
    }

    @Override
    public void onFailure(int code, String msg) {
    }

    @Override
    public void setData(T data) {
        if (data != null) {
            mIview.bindData(data);
        }
    }
}

3.调用

CommonPresent类主要作用是建立以上4个接口之间的逻辑关系,CommomPresent同时实现了IPresent和IHandler接口,表示它会同时具备发起请求和处理请求的能力,我们希望在该类中通过refresh()发起请求(可以看到实际上会交给IModel接口的实现类去请求),然后在通过setData()处理请求结果(实际上会交给IView的实现类处理)。以上的代码已经可以处理与业务解耦的网络请求,调用伪代码如下

public class SomeActivity implements IView<DataBean>{

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        CommonPresent mPresent = new CommonPresent(context, findViewById(R.id.layout_container));
        mPresent.setModel(IModelImp);//IModelImp表示IModel的实现类
        mPresent.setContent(this);
        mPresent.build();
        mPresent.refresh();
    }

    @Override
    public void bindView(View contentView) { //CommonPresent中定义bindView()会在build()的时候调用
      //findView and initView here
    }
    @Override
    public void bindData(DataBean bean) {
      //CommonPresent中执行setData()时候会将数据实体交由IView的bindData()处理
      //所以在此函数中处理结果就行,CommonPresent的setData()函数后续中会在网络请求的响应中被调用
    }
}

3.Model

接下来我们只需要编写一个IModel的实现类去请求网络完后将响应结果交给IHandler处理即可

public class ModelPool{

    public static IModel requestData(final int id) {
        return new IModel<DataBean>() { //IView中的DataBean类型必须与这里类型一致
            @Override
            public void refresh(final IHandler<DataBean> handler) {
                Map<String, Object> params = new HashMap();
                params.put("id", id);                      
                OkHttpUtils.post()              
                           .url(UrlUtils.getUrl(Constants.REQUEST_COMMODITY))
                           .params(params)
                           .build()
                           .execute(new BaseCallback<DataBean>(handler) { //BaseCallback封装了数据解析与异常处理
                                     @Override
                                     public void onSuccess(DataBean bean) {
                                       super.onSuccess(bean);
                                       handler.setData(bean);//CommonPresent的setData()中实际调用IView的bindData()处理
                                     }
                           });
            }
        };
    }
    }

这里网络请求使用的是鸿洋大神的OkHttputils,并继承CallBack自定义MyCallBack来处理数据解析和响应异常处理,代码如下:

/**GsonCallback主要用于处理数据实体的自适应泛型的解析
 * 后端接口中统一返回的数据规范定义为BaseBean,解析成功后回调onSuccess(T t)
 * 中可获取到具体业务对应的泛型类实体对象,失败则会回调onFail()**/
public abstract class GsonCallback<T> extends Callback<BaseBean<T>> {

    public Type mType;
    public GsonCallback() {
        mType = getSuperclassTypeParameter(getClass());
    }
    public void setType(Type type) {
        mType = type;
    }
    public static Type getSuperclassTypeParameter(Class<?> subclass) {
        Type superclass = subclass.getGenericSuperclass();
        if (superclass instanceof Class) {
            throw new RuntimeException("Missing type parameter.");
        }
        ParameterizedType parameterized = (ParameterizedType) superclass;
        return $Gson$Types.canonicalize(parameterized.getActualTypeArguments()[0]);
    }

    @Override
    public BaseBean<T> parseNetworkResponse(Response response, int id) throws Exception {

        String string = response.body().string();
        Logger.d("data:" + string);
        BaseBean<T> result = new Gson().fromJson(string, new TypeToken<BaseBean<T>>() {
        }.getType());

        String json = new Gson().toJson(BaseBean.getBaseBean());

        if (BaseBean.getBaseBean() != null) {
            T data = (T) new Gson().fromJson(json, mType);
            BaseBean.setBaseBean(data);
        }

        return result;
    }

    @Override
    public void onError(Call call, Exception e, int id) {
        e.printStackTrace();
        String BaseBean;
        if (e instanceof UnknownHostException) {
            BaseBean = "连接服务器失败, 请检查网络状态";
        } else if (e instanceof SocketTimeoutException) {
            BaseBean = "连接服务器超时";
        } else {
            BaseBean = "网络无法连接, 请检查网络设置!";
        }
        onFailure(1, BaseBean);
    }

    @Override
    public void onResponse(BaseBean<T> response, int id) {
        if (response.getCode() == 0 || response.getCode() == 3) {
            onSuccess(response.getCode(), response.getMessage(), response.getBaseBean());
        } else {
            onFailure(response.getCode(), response.getMessage());
        }
    }


    @Override
    public void onBefore(Request request, int id) {
        super.onBefore(request, id);
        Logger.d(request.toString());
    }

    public abstract void onSuccess(int code, String msg, T t);

    public abstract void onFailure(int code, String msg);
}

/**
 * BaseCallback中的成功失败处理都交由了IHandler处理,通过CommonPresent中的refresh()的逻辑
 * mModel.refresh(this),这里的IHandler的引用就是CommPresent当前对象,这样就实现了CommonPresent从发起
 * 网络请求(实际由IModel处理)到处理请求结果(实际由IAdaper处理)的一个闭环操作。
 **/
public class BaseCallback<T> extends GsonCallback<T> {

    private IHandler mHandler;
    public BaseCallback(IHandler handler) {
        mHandler = handler;
    }
    @Override
    public void onBefore(Request request, int id) {
        mHandler.onBefore();
    }
    @Override
    public void onSuccess(int code, String msg, T t) {
         mHandler.onSuccess(t != null);
    }
    @Override
    public void onFailure(int code, String msg) {
        mHandler.onFailure(code, msg);
    }
}

//BaseBean为一个典型的后端接口规范实体
public class BaseBean<T> {
    int    code;
    String message;
    T      t;
}

后续继续通过拓展CommonPresent可实现对contentView中加载中、加载失败、返回为空等页面的统一封装,以及列表页面的自动分页加载(待补全)。以上还需持续完善的包括:整合IHandler和IView接口为一个接口(同为View角色);解除contentView与CommonPresent的耦合,将contentView的操作交由独立封装的BaseActivity(继承IView)处理;网络请求部分整合RxJava+Retrofit(Emmm这样的话还是重新写一个比较好)。

猜你喜欢

转载自blog.csdn.net/zhangbo328/article/details/80736113