最近 RxAndroid 、MVP、MVVM 一直是 Android 程序猿茶余饭后的谈资,因而我也抱着凑热闹的态度试试了试水。这里就谈谈试水后的感觉html
要说什么是 RxAndroid ,得从 RxJava 提及。RxJava 在 GitHub 主页上的自我介绍是 “a library for composing asynchronous and event-based programs using observable sequences for the Java VM”(一个在 Java VM 上使用可观测的序列来组成异步的、基于事件的程序的库)。这就是 RxJava ,归纳得很是精准。java
RxJava 的本质能够压缩为异步这一个词。说到根上,它就是一个实现异步操做的库,而别的定语都是基于这之上的。android
而RxAndroid是RxJava的一个针对Android平台的扩展,主要用于 Android 开发。git
Retrofit 是一套 RESTful 架构的 Android(Java) 客户端实现,基于注解,提供 JSON to POJO(Plain Ordinary Java Object ,简单 Java 对象),POJO to JSON,网络请求(POST,GET, PUT,DELETE 等)封装。github
既然只是一个网络请求封装库,如今已经有了那么多的你们已经耳熟能详的网络请求封装库了,为何还要介绍它呢,缘由在于 Retrofit 是一套注解形的网络请求封装库,让咱们的代码结构更给为清晰。它能够直接解析JSON数据变成JAVA对象,甚至支持回调操做,处理不一样的结果。主要是 Retrofit 能很好的与 RxAndroid 配合使用。segmentfault
想更详细的了解 Retrofit,能够查看官方文档api
MVC(Model-View-Controller)和 MVP(Model-View-Presenter)是最多见的软件架构之一,业界有着普遍应用,你们必定不陌生。但知道什么事 MVVP 的就很少了,它自己很容易理解,可是要讲清楚,这几个架构的区别就不容易了。缓存
MVVM(Model-View-ViewModel),它采用双向绑定(data-binding):View的变更,自动反映在 ViewModel,反之亦然。Angular 和 Ember 都采用这种模式。服务器
而 Google 新推出的 Databinding 正是采用了这种模式。网络
上面已经分别介绍了 RxAndroid、Retrofit、Databinding ,想必你们也有了个初步的认识,那咱们就看看 RxAndroid + Retrofit + Databinding 产生的“化学反应”。
private void initActionBar() { setSupportActionBar(getBinding().toolbar); DrawerLayout drawer = getBinding().drawLayout; ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(this, drawer, getBinding().toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close); drawer.setDrawerListener(toggle); toggle.syncState(); getBinding().navigationView.setNavigationItemSelectedListener(this); }
代码中再也不充斥着 findViewById 这样的代码了,将 etContentView() 换成下面的方法。
this.mBinding = DataBindingUtil.setContentView(context, layout_id);
系统会将咱们的 layout 和 data 进行绑定并返回 bind 对象,bind.* 或者 bind.set 方法来取得控件或修改值。固然还有其它的方法,可是你此时再使用 findViewById() 方法再也不有效了。
public interface NewsApi { /** * 根据 ID 请求新闻列表 * @param id * @return */ @Headers("apikey: 2c61a1cd1f64216e92f7da1603697bf7") @GET(ApiConst.NEWS) Observable<News.NewsData> queryNewsByID(@Query("channelId") String id, @Query("page") int page); /** * 根据 ChannelName (标题)请求新闻列表 * @param title * @return */ @Headers("apikey: 2c61a1cd1f64216e92f7da1603697bf7") @GET(ApiConst.NEWS) Observable<News.NewsData> queryNewsByCName(@Query("channelName") String title, @Query("page") int page); /** * 根据 title (标题)请求新闻列表 * @param title * @return */ @Headers("apikey: 2c61a1cd1f64216e92f7da1603697bf7") @GET(ApiConst.NEWS) Observable<News.NewsData> queryNewsByTitle(@Query("title") String title, @Query("page") int page); }
-
private void initObservables() { Observable.Transformer<List<News>, List<News>> networkingIndicator = RxNetworking.bindRefreshing(getBinding().refresher); observableRefresherNewsData = Observable.defer(() -> mNewApi.queryNewsByCName(getArguments().getString(BUNDLE_NAME), 1)) .doOnUnsubscribe(() -> this.unsubcribe("observableNewsData")) .flatMap(data -> Observable.just(data.contentlist)) .flatMap(list -> getApp().getDB().putList(Const.DB_NEWS_NAME, list, News.class)) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .compose(networkingIndicator); observableLoadMoreNewsData = Observable.defer(() -> mNewApi.queryNewsByCName(getArguments().getString(BUNDLE_NAME), mCurrPage + 1)) .doOnUnsubscribe(() -> this.unsubcribe("observableNewsData")) .map(data -> { mCurrPage = data.currentPage; return data.contentlist; }) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .compose(networkingIndicator); // 刷新/加载更多 RxSwipeRefreshLayout.refreshes(getBinding().refresher) .doOnUnsubscribe(() -> this.unsubcribe("SwipeRefreshLayout")) .flatMap(avoid -> observableRefresherNewsData) .compose(bindToLifecycle()) .subscribe(RxList.prependTo(mNews, getBinding().content), this::showError); RxEndlessRecyclerView.reachesEnd(getBinding().content) .doOnUnsubscribe(() -> this.unsubcribe("Recycler")) .flatMap(avoid -> observableLoadMoreNewsData) .compose(bindToLifecycle()) .subscribe(RxList.appendTo(mNews), this::showError); // 首次进入手动加载 observableRefresherNewsData .map(list -> { mNews.clear(); return list; }) .compose(bindToLifecycle()) .subscribe(RxList.prependTo(mNews, getBinding().content), this::showError); }
上面代码是使用 Retrofit 以 Get 形式从服务器中获取对应的新闻数据,你们能够看到代码的逻辑很是清晰,代码也很简洁(这里使用了 lambda 表达式,不使用的话,代码会长些,可是逻辑依然清晰),若是是按之前的写法的话,咱们的代码会比这复杂的多,还涉及到复杂的线程之间的通讯。而经过 RxJava ,咱们只须要简单的使用 subscribeOn(Schedulers.io()) 和 observeOn(AndroidSchedulers.mainThread()) 就能够完成 IO 线程和 UI 线程的切换。
帅的简直不敢相信,原来还能够这样玩。
代码逻辑更多加清晰。
线程之间的切换更加方便、自如。
代码可扩展性高,便于维护。
再也不为 findViewById() 方法而烦,为 Activity 减负,总体结构更加清晰。
代码出错时,因为 RxJava 的缘由,将不太容易找到具体出错位置。
因为 RxJava 结构问题,部分须要捕捉的错误可能被 RxJava 消化掉。
Databinding 在部分状况使用不太如意,如 include 进来的 layout 里对应的 id 不会被关联起来。
须要必定的学习成本(固然这不是问题)。
RxJava / RxAndroid
极力推荐的代码家干货:http://gank.io/post/560e15be2dca930e00da1083
Retrofit:
Retrofit 官方文档:http://square.github.io/retrofit/
Retrofit 使用介绍:http://www.cnblogs.com/angeldevil/p/3757335.html
Retrofit 离线缓存策略:http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2016/0115/3873.html
Databinding
MVC,MVP 和 MVVM 的图示:http://www.ruanyifeng.com/blog/2015/02/mvcmvp_mvvm.html
DataBinding 用户指南:http://segmentfault.com/a/1190000002876984
Github 上比较全面的:https://github.com/LyndonChin/MasteringAndroidDataBinding