Android开发经验谈Android开发Android开发

Android:Retrofit + RxJava MVP 架构

2018-09-20  本文已影响94人  FindUById

前言

目前 MVP 架构在 Android app 开发中非常流行。通过 谷歌官方 例子和个人的一些理解形成自己的 Retrofit + RxJava 的 MVP 架构,并且用这实际开发当中。看此文需要一定的 Retrofit 和 RxJava 基础,对 mvp-clean 有一定了解。

MVP 简单介绍

下图分析:
V 层和 M 层直接关联了吗?并没有,这是 MVP 和 MVC 一个很大的区别。V 层和 M 层是通过 P 层联系起来的。反映到代码中就是 P 持有 V 实例和 M 实例。

MVP

具体实现

1. 总体包目录

image.png

2. 关键类的说明

public abstract class BaseMvpActivity<P extends BasePresenter<? extends IBaseView>> extends BaseActivity implements IBaseView {

    //主Presenter
    protected P mPresenter;
    //多个Presenter时候需要的容器
    private ArraySet<BasePresenter> mPresenters = new ArraySet<>(4);

    @Override
    protected void init(@Nullable Bundle savedInstanceState) {
        initLoading();
        mPresenter = getPresenter();
        addToPresenters(mPresenter);
        initView();
        initListener();
        initData();
    }

    @Override
    protected void onDestroy() {
        for (BasePresenter presenter : mPresenters) {
            presenter.detachView();
        }
        mPresenters.clear();
        super.onDestroy();
    }

    @Override
    public void showLoading() {

    }

    @Override
    public void showLoading(String msg) {

    }

    @Override
    public void hideLoading() {

    }

    @Override
    public void showMsg(String msg) {
        toastS(msg);
    }

    /**
     * 初始化Presenter,其他多个Presenter也在该方法创建并调用addToPresenters加入到集合
     * @return 主Presenter
     */
    protected abstract P getPresenter();

    /**
     * 根据具体项目需求创建loading
     */
    protected void initLoading() {

    }

    /**
     * 初始化View
     */
    protected void initView(){

    }

    /**
     * 初始化Listener
     */
    protected abstract void initListener();

    /**
     * 初始化数据
     */
    protected abstract void initData();

    /**
     * 把其他的Presenter添加到Presenters集合里
     * 这样会自动绑定View和管理内存释放
     */
    protected <T extends BasePresenter> void addToPresenters(T presenter) {
        presenter.attachView(this);
        mPresenters.add(presenter);
    }

}

public abstract class BasePresenter<V extends IBaseView> {

    private V mView;

    //Disposable容器,收集Disposable,主要用于内存泄漏管理
    private CompositeDisposable mDisposables;

    protected V getView() {
        return mView;
    }

    /**
     * @param view 绑定View
     */
    @SuppressWarnings("unchecked")
    public <T extends IBaseView> void attachView(T view) {
        this.mView = (V) view;
        mDisposables = new CompositeDisposable();
    }

    /**
     * 解绑关联
     */
    public void detachView() {
        mDisposables.clear();
        mDisposables = null;
        mView = null;
    }

    /**
     * @param disposable 添加Disposable到CompositeDisposable
     *                   通过解除disposable处理内存泄漏问题
     */
    protected boolean addDisposable(Disposable disposable) {
        if (isNullOrDisposed(disposable)) {
            return false;
        }
        return mDisposables.add(disposable);
    }

    /**
     * @param d 判断d是否为空或者dispose
     * @return true:一次任务未开始或者已结束
     */
    protected boolean isNullOrDisposed(Disposable d) {
        return d == null || d.isDisposed();
    }

    /**
     * @param d 判断d是否dispose
     * @return true:一次任务还未结束
     */
    protected boolean isNotDisposed(Disposable d) {
        return d != null && !d.isDisposed();
    }

    /**
     * 获取 Model 实例
     */
    protected <M extends IBaseModel> M getModel(Class<M> clazz) {
        return ModelManager.getInstance().create(clazz);
    }

}
public final class HttpManager {

    private Retrofit mRetrofit;
    private String mBaseUrl;
    private OkHttpClient mOkHttpClient;
    private Boolean debug = true;

    private static final Logger LOG = Logger.getLogger(HttpManager.class.getName());

    private HttpManager() {
    }

    public static HttpManager getInstance() {
        return Holder.INSTANCE;
    }

    /**
     * @param mBaseUrl 设置BaseUrl
     *                 放在第一位设置
     */
    public HttpManager setBaseUrl(String mBaseUrl) {
        this.mBaseUrl = mBaseUrl;
        return Holder.INSTANCE;
    }

    /**
     * 设置OkHttpClient
     */
    public HttpManager setOkHttpClient(OkHttpClient okHttpClient) {
        this.mOkHttpClient = okHttpClient;
        return Holder.INSTANCE;
    }

    /**
     * @param retrofit 设置retrofit
     *                 放在最后设置
     */
    public void setRetrofit(Retrofit retrofit) {
        this.mRetrofit = retrofit;
    }

    /**
     * debug
     */
    public HttpManager setDebug(Boolean debug) {
        this.debug = debug;
        return Holder.INSTANCE;
    }

    /**
     * @return mRetrofit.create(clazz)
     */
    public <T> T getApiService(Class<T> clazz) {
        return mRetrofit.create(clazz);
    }

    /**
     * 自带创建retrofit
     */
    public Retrofit createRetrofit() {
        Retrofit.Builder builder = new Retrofit.Builder()
                .baseUrl(mBaseUrl)
                .client(mOkHttpClient)
                .addConverterFactory(ScalarsConverterFactory.create())
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(ObserveOnMainCallAdapterFactory.createMainScheduler())
                .addCallAdapterFactory(RxJava2CallAdapterFactory.createWithScheduler(Schedulers.io()));
        return builder.build();
    }

    /**
     * @return OkHttpclient
     */
    public OkHttpClient createDefaultClient() {
        ...
    }

    private static class Holder {
        private static final HttpManager INSTANCE = new HttpManager();
    }

    /**
     * info 等级log
     */
    public static class InterceptorLogInfo implements HttpLoggingInterceptor.Logger {
        @Override
        public void log(@NonNull String message) {
            LOG.log(Level.INFO, message);
        }
    }

}
public abstract class HttpResultObserver<T> extends DisposableSingleObserver<T> {

    @Override
    public void onSuccess(T t) {
        //dispose 一次任务
        dispose();
        onResult(t);
    }

    @Override
    public void onError(Throwable e) {
        //dispose 一次任务
        dispose();
        onFailure(e);
    }

    /**
     * @param t 获取结果
     */
    protected abstract void onResult(T t);

    /**
     * @param e 获取结果失败
     */
    protected abstract void onFailure(Throwable e);

}
public final class ObserveOnMainCallAdapterFactory extends CallAdapter.Factory{

    private final Scheduler mScheduler;

    public ObserveOnMainCallAdapterFactory(Scheduler scheduler) {
        this.mScheduler = scheduler;
    }

    @Nullable
    @Override
    public CallAdapter<?, ?> get(@NonNull Type returnType, @NonNull Annotation[] annotations, @NonNull Retrofit retrofit) {
        Class<?> rawType = getRawType(returnType);
        if (rawType != Single.class) {
            return null;
        }
        final CallAdapter<Object, Single<?>> delegate =
                (CallAdapter<Object, Single<?>>) retrofit.nextCallAdapter(this, returnType, annotations);
        return new CallAdapter<Object, Object>() {
            @Override
            public Type responseType() {
                return delegate.responseType();
            }

            @Override
            public Object adapt(@NonNull Call<Object> call) {
                Single<?> s = delegate.adapt(call);
                return s.observeOn(mScheduler);
            }
        };
    }

    /**
     * 在android主线程处理下游数据
     */
    public static CallAdapter.Factory createMainScheduler() {
        return new ObserveOnMainCallAdapterFactory(AndroidSchedulers.mainThread());
    }
}
public final class ModelManager {

    private final ConcurrentHashMap<Class<? extends IBaseModel>, ? extends IBaseModel> DATA_CACHE;

    private ModelManager() {
        DATA_CACHE = new ConcurrentHashMap<>(8);
    }

    /**
     * @return ModelManager单例实例
     */
    public static ModelManager getInstance() {
        return Holder.INSTANCE;
    }

    private static class Holder {
        private static final ModelManager INSTANCE = new ModelManager();
    }

    /**
     * 创建获取 Model 层实例
     * @param clazz IBaseModel 子类 class
     */
    @SuppressWarnings("unchecked")
    public <M extends IBaseModel> M create(final Class<M> clazz) {

        IBaseModel model = DATA_CACHE.get(clazz);
        if (model != null) {
            return (M) model;
        }

        synchronized (DATA_CACHE) {
            model = DATA_CACHE.get(clazz);
            if (model == null) {
                try {
                    Constructor<M> constructor = clazz.getDeclaredConstructor();
                    constructor.setAccessible(true);
                    model = constructor.newInstance();
                } catch (... e) {
                ....
                }
            }
        }
        return (M) model;
    }

}

更多代码细节可以去 我的GitHub 看下。

3. 使用方式

以在一个 Activity 请求 GitHub 两个接口为例,一个接口请求个人用户信息,一个接口请求公司用户信息,所以例子将模拟两个模块,user 和 orgs 。使用过程中你会发现一个View 可以有多个 Presenter,一个 Activity 可以实现多个 View 接口。其实还不止这些,其实 Presenter 也可以用有多个 Model。
完整例子

Android:Retrofit + RxJava MVP 架构实际应用
package ${PACKAGE_NAME};
#parse("File Header.java")
public interface ${NAME}{
    interface View extends IBaseView{
    }
    interface Presenter{   
    }
}
目录结构
public class SimpleApplication extends Application {

    @Override
    public void onCreate() {
        super.onCreate();
        HttpManager.getInstance()
                .setBaseUrl("https://api.github.com/")
                .setDebug(BuildConfig.DEBUG)
                .setOkHttpClient(HttpManager.getInstance().createDefaultClient())
                .setRetrofit(HttpManager.getInstance().createRetrofit());
    }

}
public class MainActivity extends BaseMvpActivity<UserPresenter> implements UserContract.View, OrgContract.View {
      ...
    //公司信息Presenter(次Presenter)
    private OrgPresenter mOrgPresenter;

    private ProgressDialog mLoading;

    @Override
    protected int getLayoutId() {
        return R.layout.activity_main;
    }

    @Override
    protected void initLoading() {
        mLoading = new ProgressDialog(this);
    }

    @Override
    protected UserPresenter getPresenter() {
        mOrgPresenter = new OrgPresenter();
        addToPresenters(mOrgPresenter);
        return new UserPresenter();
    }

    @Override
    protected void initView() {
       ...
    }

    @Override
    protected void initListener() {

        //点击获取个人信息
        btnClick.setOnClickListener(new android.view.View.OnClickListener() {
            @Override
            public void onClick(android.view.View v) {
                mPresenter.getUser("togallop");
            }
        });

        //点击获取用户信息
        btnClick2.setOnClickListener(new android.view.View.OnClickListener() {
            @Override
            public void onClick(android.view.View v) {
                mOrgPresenter.getOrg("google");
            }
        });
    }

    @Override
    public void showUser(String msg) {
        tvMsg.setText(msg);
    }

    @Override
    public void showOrg(String org) {
        tvMsg.setText(org);
    }

    @Override
    public void showLoading(String msg) {
        mLoading.setMessage(msg);
        if (!mLoading.isShowing()) {
            mLoading.show();
        }
    }

    @Override
    public void showLoading() {
        if (!mLoading.isShowing()) {
            mLoading.show();
        }
    }

    @Override
    public void showMsg(String msg) {
        toastS(msg);
    }

    @Override
    public void hideLoading() {
        if (mLoading.isShowing()) {
            mLoading.dismiss();
        }
    }
}

public class UserPresenter extends BasePresenter<UserContract.View> implements UserContract.Presenter {

    private UserModel mModel;

    public UserPresenter() {
        mModel = getModel(UserModel.class);
    }

    @Override
    public void getUser(String userName) {

        //做一些判断
        if (TextUtils.isEmpty(userName)) {
            getView().showMsg("用户名不能为空");
            return;
        }

        //显示loading
        getView().showLoading("正在加载...");
        Disposable disposable = mModel.getUser(userName, new HttpResultObserver<String>() {
            @Override
            protected void onResult(String s) {
                //结果回调显示
                getView().showUser(s);
                getView().hideLoading();
            }

            @Override
            protected void onFailure(Throwable e) {
                //获取数据是失败回调处理
                getView().showMsg(e.getMessage());
                getView().hideLoading();
            }
        });
        addDisposable(disposable);
    }
}
public class UserModel extends BaseModel {

    public Disposable getUser(String userName, HttpResultObserver<String> observer) {
        return getApiService().getUser(userName).subscribeWith(observer);
    }

}
public interface ApiService {

    @GET("users/{username}")
    Single<String> getUser(@Path("username") String userName);

    @GET("orgs/{org}")
    Single<String> getOrg(@Path("org") String org);

}

对于有后台有固定返回格式的的数据,也可以统一处理。比如返回结果类似这样的:

{
    code:200
    msg:"success"
    data:{}
}

那么可以这么处理,创建回调泛型类

public abstract class HttpResultObserver2<T> extends HttpResultObserver<Result<T>> {

    @Override
    public void onSuccess(Result<T> t) {
        switch (t.code) {
            case 200:
                onSuccess(t.data);
                break;
            default: {
                HttpResultException e = new HttpResultException(t.code, t.msg);
                toast(e.getMsg());
                onFailure(HttpError.RESULT_ERROR, e);
                e.printStackTrace();
                break;
            }
        }
    }

    @Override
    public void onError(Throwable t) {
        onFailure(error, (Exception) t);
    }

    /**
     * 请求成功回调
     *
     * @param result 回调数据
     */
    public abstract void onResult(T result);

    /**
     * 请求失败回调
     *
     * @param error,自定义异常
     * @param e     失败异常信息
     */
    public abstract void onFailure(HttpError error, @NonNull Exception e);

}

APIService:Single 泛型类型为 <Result<xxx>>

Single<Result<String>> uploadImage(...)

使用方式和上面介绍的一样。

总结

MVP 架构是死的,具体实现是活的;任何离开具体业务的代码都是不现实的,我的这部分代码只是一个参考,可以根据具体需求在我的这份代码上扩展,实现自己的需求。举些例子:要统一处理异常信息,可以继承 HttpResultObserver 统一处理异常;处理内存泄漏也可以有很多方式,RxLifecycle/Reference/LifeCycle 等;不一定要用 Single,用 Flowable/Maybe 等都行,看具体需要,网络请求是一次性的,所以我用 Single,处理也方便。总而言之,最好的不一定适合你,适合你的才是最好的。

上一篇 下一篇

猜你喜欢

热点阅读