Android使用Rxjava+Retrofit+OkHttp+RxLifecycle+MVP搭建项目框架

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/wb_001/article/details/82387728

之前写过一个类似的框架搭建,但是遗留下了一个问题就是,Rxjava中的订阅何如与项目中的Activity和Fragment如何绑定生命周期,避免内存泄漏以及抛出一些异常问题,这里使用了RxLifecycle。不多说,上代码。(该例子中使用的Rxjava,RxLifecycle都是2.0以下的,2.0上手难度有点高,况且我1.0还不懂)。

一、Presenter基类:

public abstract class BasePresenter<V> implements Presenter<V> {
    protected WeakReference<V> weakReference;

    @Override
    public void attachView(V view) {
        this.weakReference = new WeakReference<V>(view);
    }

    protected V getView(){
        return weakReference.get();
    }
    @Override
    public void detachView() {
        if (weakReference != null){
            weakReference.clear();
            weakReference = null;
        }
    }
}

这里还有Presenter基类里面的两个接口,用于绑定以及解绑view

public interface Presenter<V> {

    void attachView(V view);
    void detachView();
}

二、Activity基类,基类继承RxLifeCycle中的RxAppCompatActivity,用于生命周期的绑定:

public abstract class BaseActivity<V,P extends BasePresenter<V>> extends RxAppCompatActivity{
    public Activity mActivity;
    public P mPresenter;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mActivity = this;
        mPresenter = createPresenter();
    }

    @Override
    protected void onResume() {
        super.onResume();
        mPresenter.attachView((V)this);
    }

    protected abstract P createPresenter();


    @Override
    protected void onDestroy() {
        if (mPresenter != null){
            mPresenter.detachView();
        }
        super.onDestroy();
    }
}

三、Fragment基类,同理:


public abstract class BaseFragment<V,P extends BasePresenter<V>> extends RxFragment {
    public Activity mActivity;
    public P mPresenter;

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        this.mActivity = activity;
    }

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        mPresenter = createPresent();
        return super.onCreateView(inflater, container, savedInstanceState);
    }

    @Override
    public void onResume() {
        super.onResume();
        mPresenter.attachView((V)this);
    }

    protected abstract P createPresent();

    @Override
    public void onDestroy() {
        if (mPresenter != null) {
            mPresenter.detachView();
        }
        super.onDestroy();
    }
}

我这里的attachView()方法是放在onResume()方法中,有人放在onCreate/onCreateView中,我觉得这样肯能会出问题,就是当返回某界面时,该界面已经执行了onDestroy()方法,也就是说,把View的弱引用消除了,这时就可能会抛异常了。应该是这样吧?我也是自己瞎想的。

四、Module的基类,这里就是将观察者与被观察者关联起来,同时使用bindUntilEvent绑定Activity的生命周期,以至于当Activity执行onDestroy()时,观察者与被观察者解除订阅关系,这样就可以防止内存泄漏等问题。

public class BaseModule {
    protected BaseActivity baseActivity;
    protected BaseFragment baseFragment;

    public BaseModule(BaseActivity baseActivity) {
        this.baseActivity = baseActivity;
    }

    public BaseModule(BaseFragment baseFragment) {
        this.baseFragment = baseFragment;
    }

    protected <T> void doActivitySubscribe(Observable<T> observer, Subscriber<T> subscriber){
       observer.subscribeOn(Schedulers.io())
               .observeOn(AndroidSchedulers.mainThread())
               .compose(baseActivity.<T>bindUntilEvent(ActivityEvent.DESTROY))
               .subscribe(subscriber);
    }

    protected <T> void doFragmentSubscribe(Observable<T> observer, Subscriber<T> subscriber){
        observer.subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .compose(baseFragment.<T>bindUntilEvent(FragmentEvent.DESTROY))
                .subscribe(subscriber);
    }

}

五,接下来看Subscriber观察者,这里面有一些对网络请求的处理:

public abstract class HttpSubscriber<T> extends Subscriber<BaseBen<T>> {
    private Context context;
    private boolean isShowDialog;
    private LoadingDialog loadingDialog;


    public HttpSubscriber(Context context, boolean isShowDialog) {
        this.context = context;
        this.isShowDialog = isShowDialog;
    }

    @Override
    public void onStart() {
        super.onStart();
        Log.i("tag","onStart");
        if (InternetUtil.isNetWorking(context)){
            if (loadingDialog ==null && isShowDialog){
                loadingDialog = new LoadingDialog.Builder(context).create();
                loadingDialog.show();
            }
        }else {
            Toast.showToast(context,"暂无网络");
            onError("暂无网络");
            if (!isUnsubscribed()){
                unsubscribe();
            }
        }
    }

    @Override
    public void onCompleted() {
        Log.i("tag","onCompleted");
        if (!isUnsubscribed()){
            unsubscribe();
        }
        if (loadingDialog != null && isShowDialog && loadingDialog.isShowing()){
            loadingDialog.dismiss();
            loadingDialog = null;
        }
    }

    @Override
    public void onError(Throwable e) {
        Log.i("tag","onErrorMessage:"+e.getMessage());
        if(e instanceof Exception){
            if ( e instanceof JsonParseException ||e instanceof JSONException){
                onError("数据解析异常");
                Toast.showToast(context,"数据解析异常");
            }else if (e instanceof ConnectException){
                onError("网络连接异常");
                Toast.showToast(context,"网络连接异常");
            }else if (e instanceof SocketTimeoutException){
                onError("请求超时");
                Toast.showToast(context,"请求超时");
            }else if (e instanceof HttpException){
                Toast.showToast(context,"服务异常");
                onError("服务器异常");
            }else if (e instanceof UnknownHostException){
                Toast.showToast(context,"服务Host异常");
                onError("服务Host异常");
            }else {
                onError("未知异常");
                Toast.showToast(context,"异常:"+e.getMessage());
            }
        }else {
            onError("未知异常");
            Toast.showToast(context,"未知异常");
        }
        if (loadingDialog != null && isShowDialog && loadingDialog.isShowing()){
            loadingDialog.dismiss();
            loadingDialog = null;
        }
    }

    @Override
    public void onNext(BaseBen<T> tBaseBen) {
        onSuccess(tBaseBen);
    }


    public abstract void onSuccess(BaseBen<T> tBaseBen);
    public abstract void onError(String msg);
}

六,对返回的bean进行封装


public class BaseBen<T> {
    private int code;
    private String msg;
    private T data;

    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }
}

七,接下来是网络层:OkHttp+Retrofit

public class HttpClient {

    private Retrofit retrofit;

    private static final int DEFAULT_TIMEOUT = 10;
    //cookie持久化
    private static ClearableCookieJar cookieJar = new PersistentCookieJar(new SetCookieCache(), new SharedPrefsCookiePersistor(MyApplication.getMyApplication()));
    //设置缓存目录
    private static final File cacheDirectory = new File(MyApplication.getMyApplication().getCacheDir().getAbsolutePath(), "httpCache");
    private static Cache cache = new Cache(cacheDirectory, 10 * 1024 * 1024);
    //构造方法私有
    private HttpClient() {
        // 创建一个OkHttpClient
        OkHttpClient.Builder builder = new OkHttpClient.Builder();
        // 设置网络请求超时时间
        builder.readTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS);
        builder.writeTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS);
        builder.connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS);
        builder.cookieJar(cookieJar);
        // 失败后尝试重新请求
        builder.retryOnConnectionFailure(false);
        builder.addInterceptor(new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() {
            @Override
            public void log(String message) {
                Log.i("http", message);
            }
        }).setLevel(HttpLoggingInterceptor.Level.BODY));
        builder.cache(cache);
        //----------------------------基本设置------------------------------------------------------
        retrofit = new Retrofit.Builder()
                .client(builder.build())
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                .baseUrl(Constant.BASE_URL)
                .build();
    }

    /**
     * 调用单例对象
     */
    private static HttpClient getInstance() {
        return SingletonHolder.INSTANCE;
    }

    /**
     * 创建单例对象
     */
    private static class SingletonHolder {
        static HttpClient INSTANCE = new HttpClient();
    }

    /**
     * @return 指定service实例
     */
    public static <T> T getService(Class<T> clazz) {
        return HttpClient.getInstance().retrofit.create(clazz);
    }
}

这里用到了一个Cookie持久化的框架,有的后台项目可能是从session里面去取你的登录标志,比如Token,而在OkHttp中每次请求的Cookie不一样,导致第二次请求的时候服务端拿不到你的登录状态,所以无法请求到你的数据。

八、Retrofit框架中使用的请求方法:

public interface RequestApi {

    @FormUrlEncoded
    @POST("/demo/test")
    Observable<BaseBen<JsonObject>> login(@Field("name")String name,@Field("psw")String psd);

}

最后,我们看看怎么使用,我这里模拟一个登录,给服务端送入一个用户名和密码,首先,写View层,三个方法,一个获取名字,一个获取密码,然后就是更新View

public interface ITestView {
    String getName();
    String getPsw();
    void update(BaseBen<JsonObject> object);
}

再写Model层:

public class TestModel extends BaseModule {
    public TestModel(BaseActivity baseActivity) {
        super(baseActivity);
    }

    public void login(final String name,final String psw,final OnRequestCallback onRequestCallback){
        doActivitySubscribe(HttpClient.getService(RequestApi.class).login(name,psw),new HttpSubscriber<JsonObject>(baseActivity,true){

            @Override
            public void onSuccess(BaseBen<JsonObject> jsonObjectBaseBen) {
                onRequestCallback.onSuccess(jsonObjectBaseBen);
                Log.i("tag","loginonSuccess");
            }

            @Override
            public void onError(String msg) {
                onRequestCallback.onFailed(msg);
                Log.i("tag","loginonError:"+msg);
            }

        });
    }

    public interface OnRequestCallback{
        void onSuccess(BaseBen<JsonObject> jsonObjectBaseBen);
        void onFailed(String msg);
    }
}

然后就就是Presenter,执行登录动作逻辑:

public class TestPresenter extends BasePresenter<ITestView> {
    private ITestView iTestView;
    private TestModel testModel;

    public TestPresenter(ITestView iTestView, BaseActivity activity) {
        this.iTestView = iTestView;
        testModel = new TestModel(activity);
    }

    public void login(){
        testModel.login(iTestView.getName(), iTestView.getPsw(), new TestModel.OnRequestCallback() {
            @Override
            public void onSuccess(BaseBen<JsonObject> jsonObjectBaseBen) {
                iTestView.update(jsonObjectBaseBen);
            }

            @Override
            public void onFailed(String msg) {

            }
        });
    }
}

看看Activity是这么写的:

public class TestActivity extends BaseActivity<ITestView,TestPresenter> implements ITestView {

    @InjectView(R.id.name)
    EditText name;
    @InjectView(R.id.psw)
    EditText psw;
    @InjectView(R.id.btn)
    Button btn;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ButterKnife.inject(this);
    }

    @Override
    protected TestPresenter createPresenter() {
        return new TestPresenter(this,this);
    }

    @OnClick(R.id.btn)
    public void onViewClicked(View view) {
        switch (view.getId()){
            case R.id.btn:
                mPresenter.login();
                break;
        }
    }

    @Override
    public String getName() {
        return name.getText().toString();
    }

    @Override
    public String getPsw() {
        return psw.getText().toString();
    }

    @Override
    public void update(BaseBen<JsonObject> object) {

    }
}

好了,完了,这个MVP模式可能我个人认为是最简单的写法,MVP模式其实有很多种写法,见笑了。
最后,感谢这位的学习资源,谢谢

附demo源码:源码下载 !!!

猜你喜欢

转载自blog.csdn.net/wb_001/article/details/82387728