Android关于Retrofit+Rxandroid+lifecycle在vc架构的封装和使用

        最近正在做一个项目,架构呢就是使用的第一篇博客所描述的架构。在业务模块中,ui框架使用了不严谨的mvc架构,摒弃了m层,把m层与c层合并到了一起,也就是vc模式的架构。一个View与一个Controller一一对应,那么操作逻辑和网络请求在controller中执行,然后view中根据数据做出响应。

        该框架的封装要感谢我的俩同事, @朱小蛟 和 @马小飞,代码大部分都是他们搞的。

1.涉及框架

        一,Retrofit。一个RESTful 的HTTP网络请求框架(基于OKHttp),通过注解配置网络请求参数,支持同步,异步网络请求,支持多种数据的解析,并提供对RxJava的支持。优点很多,拓展性好,简洁易用,高解耦等等吧。

    compile "com.squareup.retrofit2:adapter-rxjava:$rootProject.adapterRxjavaVersion"
    compile "com.squareup.retrofit2:retrofit:$rootProject.retrofitVersion"
    compile "com.squareup.retrofit2:converter-gson:$rootProject.converterGsonVersion"

        二,RxAndroid。rxandroid是rxjava在android上的一个扩展,这个库用来处理事件,异步任务。该库,怎么说,就俩字,简洁。当业务十分繁琐复杂时这一点就显出优势了,依然可以保持简洁。

    compile "io.reactivex:rxandroid:$rootProject.rxandroidVersion"

        三,LifeCycle。这是Google官方在I/O大会中引出的新架构内容之一,它实现的一个重要目的,时实现Android的与Activity和Fragment生命周期相关的逻辑控制进一步的解耦。以前因为要写与activity 和 fragment 生命周期相关的控制逻辑的时候,不得不在activity或fragment的onCreate,onStart,onResume里面塞进自己的代码,这样就会让页面中的代码越来越多。而lifecycle专注于activity或者fragment生命周期的维护管理。

    compile "android.arch.lifecycle:extensions:$rootProject.lifecycleExtensionsVersion"
    annotationProcessor "android.arch.lifecycle:compiler:$rootProject.lifecycleCompilerVersion"
2.代码走起

        1.因为是vc模式,v中会调用一些c中的逻辑方法,c中会有很多地方调用网络请求,或者调用操作逻辑,所以先创建一个BaseController,以统一controller对一些逻辑的编写。

        ViewModel是lifecycle中的一个抽象类,目的是将数据从ui中分离出来,并且当activity或者fragment重构的时候,viewmodel会自动保留之前的数据并给新的activity或fragment使用。

public abstract class BaseController extends ViewModel {

    @Override
    protected void onCleared() {
        
    }
}

        然后因为需要通过响应式对数据做传递,则需要订阅者集合,并创建网络请求和逻辑操作的公有方法。

public abstract class BaseController extends ViewModel {

	/**
     * RxJava 的订阅者集合
     */
    protected CompositeSubscription mSubscriptions = new CompositeSubscription();

	/**
     * 封装网络请求
     *
     * @param observable 被观察者,url
     * @param observer   回调
     * @param <T>        解析后的实体
     */
    protected <T> void getHttpData(Observable<T> observable, Observer<T> observer) {
        Subscription subscription = observable.subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread()).subscribe(observer);
        mSubscriptions.add(subscription);
    }

    /**
     * 无网络请求的操作请求
     * @param t        承载数据的数据体
     * @param observer 回调
     * @param <T>      解析后的实体
     */
    protected <T> void getOperateData(final T t, Observer<T> observer){
        Observable<T> observable = Observable.create(new Observable.OnSubscribe<T>() {
            @Override
            public void call(Subscriber<? super T> subscriber) {
                subscriber.onNext(t);
                subscriber.onCompleted();
            }
        });
        mSubscriptions.add(observable.subscribe(observer));
    }

    @Override
    protected void onCleared() {
        // 取消订阅
        mSubscriptions.clear();
    }
}

        ok,此时basecontroller就基本好了。现在就看看retrofit如何进行一个封装吧。创建一个HttpUtil。直接上代码,看代码秒懂。

public class HttpUtil {

    private static OkHttpClient okHttpClient;
    private static Converter.Factory gsonConverterFactory = GsonConverterFactory.create();
    private static CallAdapter.Factory rxJavaCallAdapterFactory = RxJavaCallAdapterFactory.create();
    private static Retrofit retrofit;

    public static <T> T getRetrofit(final Class<T> service) {
        if (okHttpClient == null) {
            OkHttpClient.Builder client = new OkHttpClient.Builder();
            // 添加http请求json数据打印
            client.addInterceptor(new LoggingInterceptor.Builder()
                    .loggable(BuildConfig.DEBUG)
                    .setLevel(Level.BASIC)
                    .log(Platform.INFO)
                    .request("Request")
                    .response("Response")
                    .build()).connectTimeout(5, TimeUnit.SECONDS);
            // TODO: 2018/2/1 添加 StringCallBackInter 拦截器ø
            okHttpClient = client.build();
        }

        if (retrofit == null) {
            retrofit = new Retrofit.Builder()
                    .client(okHttpClient)
                    .baseUrl(ENV.getHttpHost())
                    .addConverterFactory(gsonConverterFactory)
                    .addCallAdapterFactory(rxJavaCallAdapterFactory)
                    .build();
        }
        return retrofit.create(service);
    }
}

        这两个写好之后,下面写一个例子,看如何使用。有一个可上拉加载下拉刷新的页面,来看看数据如何调用,如何获取。先创建一个controller继承basecontroller。并创建下拉刷新和上拉加载的方法。

    public class  TestHttpController extends BaseController {

    /**
     * 刷新
     */
    private MutableLiveData<ResultBean> mObservableRefresh;
    /**
     * 加载更多
     */
    private MutableLiveData<ResultBean> mObservableLoadMore;

    /**
     * 角色权限集合
     */
    private MutableLiveData<PermissionRoleListBean> permissionRoleListData;

    private int mPage;

    public MutableLiveData<ResultBean> getRefreshData() {
        mObservableRefresh = new MutableLiveData<>();
        getCategoryItems(true);
        return mObservableRefresh;
    }

    public MutableLiveData<ResultBean> getLoadMoreData() {
        mObservableLoadMore = new MutableLiveData<>();
        getCategoryItems(false);
        return mObservableLoadMore;
    }

    private void getCategoryItems(final boolean isRefresh) {
        if (isRefresh) {
            mPage = 1;
        }

        getHttpData(HttpUtil.getRetrofit(ManagerUrls.class).getCategoryData("Android", 20, mPage),
                new Observer<ResultBean>() {
                    @Override
                    public void onCompleted() {

                    }

                    @Override
                    public void onError(Throwable e) {
                        if (isRefresh) {
                            mObservableRefresh.setValue(null);
                        } else {
                            mObservableLoadMore.setValue(null);
                        }
                    }

                    @Override
                    public void onNext(ResultBean resultBean) {
                        if (isRefresh) {
                            mObservableRefresh.setValue(resultBean);
                        } else {
                            mObservableLoadMore.setValue(resultBean);
                        }
                        mPage += 1;
                    }
                });
    }

}

        看页面中如何使用吧。

@Route(path = "/testa/testhttp")
public class TestHttpActivity extends BaseActivity implements OnRefreshLoadmoreListener {

    @BindView(R2.id.recyclerview)
    RecyclerView recyclerview;
    @BindView(R2.id.refresh)
    SmartRefreshLayout refresh;

    private TestHttpController testHttpController;
    private TestHttpAdapter testHttpAdapter;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_test_http);
        ButterKnife.bind(this);
        initView();

        // 获取 ViewModel
        testHttpController = ViewModelProviders.of(this).get(TestHttpController.class);

        getRefreshData();
    }

    private void initView() {
        refresh.setOnRefreshLoadmoreListener(this);

        testHttpAdapter = new TestHttpAdapter(null);
        recyclerview.setLayoutManager(new LinearLayoutManager(this));
        recyclerview.setAdapter(testHttpAdapter);
    }

    @Override
    public void onRefresh(RefreshLayout refreshlayout) {
        getRefreshData();
    }

    @Override
    public void onLoadmore(RefreshLayout refreshlayout) {
        getLoadMoreData();
    }

    private void getRefreshData() {
        testHttpController.getRefreshData().observe(this, new Observer<ResultBean>() {
            @Override
            public void onChanged(@Nullable ResultBean resultBean) {
                refresh.finishRefresh();
                if (resultBean == null || resultBean.error) {
                    Toast.makeText(TestHttpActivity.this, "刷新失败", Toast.LENGTH_SHORT).show();
                    return;
                }
                testHttpAdapter.setNewData(resultBean.results);
            }
        });
    }

    private void getLoadMoreData() {
        testHttpController.getLoadMoreData().observe(this, new Observer<ResultBean>() {
            @Override
            public void onChanged(@Nullable ResultBean resultBean) {
                refresh.finishLoadmore();
                if (resultBean == null || resultBean.error) {
                    return;
                }
                testHttpAdapter.addData(resultBean.results);
            }
        });
    }

    @Override
    public void permissionSuccess(int requestCode, List<String> perms) {

    }

    @Override
    public void permissionFaild(int requestCode, List<String> perms) {

    }


}

        这样就ok了。但是当有网络请求的时候,我们需要调用一些loading弹框等等ui上的操作,就需要经常在页面方法里去编写一些show方法,dissmiss方法等等,虽然没几行代码,但是有时候很容易忘掉,一旦忘掉,那么逻辑操作就会很不友好,还得返回去加上。那么我们就对Observer做一个封装,把一些必须的逻辑放在baseobserver中,那就可以专注逻辑代码了。

public class BaseObserver<T> implements Observer<T> {

    private Context context;
    private BaseObserverListener mlistener;
    private QMUITipDialog qmDialog = null;
    private Handler mCancelHandler;

    public BaseObserver() {
        this(null, null);
    }

    public BaseObserver(Context context, BaseObserverListener listener) {
        try {
            this.context = context;
            mlistener = listener;
            mCancelHandler = new Handler();
            if (null != context) {
                // android.view.WindowLeaked: Activity com.sound.wisdomcloud.ui.activity.SplashActivity has leaked window DecorView@5300feb[] that was originally added here
                // 写在静态类里会报这个异常,所以只能维护在这里边了。
                if (null == qmDialog) {
                    qmDialog = new QMUITipDialog.Builder(context)
                            .setIconType(QMUITipDialog.Builder.ICON_TYPE_LOADING)
                            .setTipWord("正在加载")
                            .create();
                }

                Log.e("窗体泄漏", "构造 qmDialog.show();");
                qmDialog.show();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onCompleted() {

        try {
            if (null != qmDialog) {
                qmDialog.dismiss();
            }

            if (null != mlistener) {
                mlistener.onCompleted();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onError(Throwable e) {

        try {

            if (context == null) {
                return;
            }

            if (null == qmDialog) {
                qmDialog = new QMUITipDialog.Builder(context)
                        .setIconType(QMUITipDialog.Builder.ICON_TYPE_FAIL)
                        .setTipWord("请求失败")
                        .create();
            }

            Log.e("窗体泄漏", "onError qmDialog.show()");
            qmDialog.show();

            if (null != mlistener) {
                mlistener.onError(e);
            }

            if (null == mCancelHandler) {
                mCancelHandler = new Handler();
            }

            mCancelHandler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    onCompleted();
                }
            }, 2000);
        } catch (Exception ex) {
            ex.printStackTrace();
        }

    }

    @Override
    public void onNext(T o) {
        if (null != mlistener) {
            mlistener.onNext(o);
        }
    }

    public interface BaseObserverListener<T> {
        public void onCompleted();

        public void onError(Throwable e);

        public void onNext(T o);
    }

}
        把loading弹框,error弹框,等等ui上的操作都封装到baseobserver中,然后当我们调用controller的逻辑方法时,就不用再调用什么showLoading啊,请求完成之后也不用再调用dismissLoading啊等等的方法了。


        

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值