RxJava系列7(最佳实践)

作者: 张磊BARON | 来源:发表于2016-10-21 16:34 被阅读2324次
图片来自网络

转载请注明出处:http://www.jianshu.com/p/b0d8d3a5d3fc

前言

有点标题党了,其实谈不上什么最佳实践。前段时间公司实行996,所以也没什么时间和精力来更新博客(好吧我承认是我懒)。因此这篇文章只是简单的通过两个例子介绍了RxJava在生产环境中的使用。不过本篇中的每个例子我都配上了完整的代码。

按照计划这一期是要介绍RxJava框架结构和设计思想的,但是考虑到Netflix将在十月底发布RxJava2.0正式版;因此决定将RxJava框架结构和设计思想分析放到2.0正式版发布后再做。后续我也会有一系列的文章来介绍RxJava1.x和2.x的区别。

示例一、获取手机上已安装的App

第一个例子我们需要在Android设备上展示已安装的第三方app列表,关于环境搭建、依赖配置、RecyclerView的使用等这些基础内容我就不做陈述了。需要了解的同学可以去GitHub上把项目clone下来看看。这里我主要讲讲如何通过RxJava实现核心功能。

首选我们需要调用系统api来获取所有已安装的app,所以在OnSubscribecall方法中调用getApplicationInfoList()。但是getApplicationInfoList()获取的数据并不能完全满足我们的业务需求:

  1. 由于我们只需要展示手机上已安装的第三方App,因此需要通过filter操作符来过滤掉系统app;
  2. ApplicationInfo并不是我们所需要的类型,因此需要通过map操作符将其转换为AppInfo
  3. 由于获取ApplicationInfo、过滤数据、转换数据相对比较耗时,因此需要通过subscribeOn操作符将这一系列操作放到子线程中来处理;
  4. 而要将信息展示在页面上涉及到UI操作,因此需要通过observeOn操作符将onNextonCompletedonError调度到主线程,接着我们在这些方法中更新UI。

下面是核心代码:

final PackageManager pm = MainActivity.this.getPackageManager();
Observable.create(new Observable.OnSubscribe<ApplicationInfo>() {
        @Override
        public void call(Subscriber<? super ApplicationInfo> subscriber) {
            List<ApplicationInfo> infoList = getApplicationInfoList(pm);
            for (ApplicationInfo info : infoList) {
                subscriber.onNext(info);
            }
            subscriber.onCompleted();
        }
    }).filter(new Func1<ApplicationInfo, Boolean>() {
        @Override
        public Boolean call(ApplicationInfo applicationInfo) {
            return (applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) <= 0;
        }
    }).map(new Func1<ApplicationInfo, AppInfo>() {

        @Override
        public AppInfo call(ApplicationInfo applicationInfo) {
            AppInfo info = new AppInfo();
            info.setAppIcon(applicationInfo.loadIcon(pm));
            info.setAppName(applicationInfo.loadLabel(pm).toString());
            return info;
        }
    }).subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe(new Subscriber<AppInfo>() {
        @Override
        public void onCompleted() {
            mAppListAdapter.notifyDataSetChanged();
            mPullDownSRL.setRefreshing(false);
        }

        @Override
        public void onError(Throwable e) {
            mPullDownSRL.setRefreshing(false);
        }

        @Override
        public void onNext(AppInfo appInfo) {
            mAppInfoList.add(appInfo);
        }
    });

程序执行效果图:


效果图

完整的代码我放到了GitHub上,有兴趣大家可以去clone下来自己运行看看。

源码地址:https://github.com/BaronZ88/HelloRxAndroid

示例二、RxJava+Retrofit2实现获取天气数据

RxJava + Retrofit2几乎是Android应用开发的标配了,这个例子中我们就来聊聊这二者是如何配合起来帮助我们快速开发的。

Retrofit2中一个标准的接口定义是这样的:

@GET("weather")
Observable<Weather> getWeather(@Query("cityId") String cityId);

现在有了RxJava,一个基本的网络请求我们便可以这样实现:

ApiClient.weatherService.getWeather(cityId)
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Action1<Weather>() {
                    @Override
                    public void call(Weather weather) {
                        weatherView.displayWeatherInformation(weather);
                    }
                });

但有时候可能一开始我们并不知道cityId,我们只知道cityName。所以就需要我们先访问服务器,拿到对应城市名的cityId,然后通过这个cityId再去获取天气数据。

同样的,我们需要定义一个获取cityId的接口:

@GET("city")
Observable<String> getCityIdByName(@Query("cityName") String cityName);

紧接着我们便可以使用无所不能的RxJava来实现需求了。

ApiClient.weatherService.getCityIdByName("上海")
             .flatMap(new Func1<String, Observable<Weather>>() {
                 @Override
                 public Observable<Weather> call(String cityId) {
                     return ApiClient.weatherService.getWeather(cityId);
                 }
             }).subscribeOn(Schedulers.io())
             .observeOn(AndroidSchedulers.mainThread())
             .subscribe(new Action1<Weather>() {
                 @Override
                 public void call(Weather weather) {
                     weatherView.displayWeatherInformation(weather);
                 }
             });

哇哦!~ so easy!!!妈妈再也不用担心....

源码地址:https://github.com/BaronZ88/WeatherStyle

WeatherStyle这个项目还在开发中,这个项目不只包含了RxJava和Retrofit的使用,同时还包含MVP、ORMLite、RetroLambda、ButterKnife等等开源库的使用

RxJava1.X的系列文章就到此结束了,由于本人对RxJava的理解有限,这一系列文章中如有错误还请大家指正。在使用RxJava过程中有任何疑问也欢迎大家和我交流。共同学习!共同进步!

好啦,我们RxJava2见!~


如果大家喜欢这一系列的文章,欢迎关注我的知乎专栏、GitHub、简书博客。

相关文章

网友评论

  • 72c35595f71b:不错。
  • a3238341c037:磊哥好,最近在学习RxJava。关于你的第一个应用场景有问题想问下。

    ① 在不使用异步的情况下,代码如下
    PackageManager pm = MainActivity.this.getPackageManager();
    List<ApplicationInfo> infoList = getApplicationInfoList(pm); // 耗时操作
    for (ApplicationInfo info : infoList) {
    if (info.flags & ApplicationInfo.FLAG_SYSTEM <= 0) {
    AppInfo appInfo = new AppInfo();
    appInfo.setAppIcon(info.loadIcon(pm));
    appInfo.setAppName(info.loadLabel(pm).toString()); // 耗时操作
    mAppInfoList.add(appInfo);
    }
    }
    mAppListAdapter.notifyDataSetChanged(); // 主线程
    mPullDownSRL.setRefreshing(false); // 主线程

    ② 你举例的时候说“获取ApplicationInfo、过滤数据、转换数据相对比较耗时”,那我可以使用以前用的,通过回调监听的方式,来改成如下代码:

    // 通过回调接口的方式
    public static interface OnCompleteListener {
    void onCompleted(List<AppInfo> appInfos);
    }
    void getApplicationInfoList(PackageManager pm, final OnCompleteListener listener) {
    final List<AppInfo> results = new ArrayList<AppInfo>();
    new Thread() {
    List<ApplicationInfo> infoList = getApplicationInfoList(pm); // 耗时操作
    for (ApplicationInfo info : infoList) {
    if (info.flags & ApplicationInfo.FLAG_SYSTEM <= 0) {
    AppInfo appInfo = new AppInfo();
    appInfo.setAppIcon(info.loadIcon(pm));
    appInfo.setAppName(info.loadLabel(pm).toString()); // 耗时操作
    results.add(appInfo); // 主线程
    }
    }
    listener.onCompleted(results);
    }.run();
    }
    PackageManager pm = MainActivity.this.getPackageManager();
    getApplicationInfoList(pm, new OnCompleteListener() {
    @Override
    void onCompleted(List<AppInfo> appInfos) {
    mAppListAdapter.setList(appInfos);
    mAppListAdapter.notifyDataSetChanged();
    mPullDownSRL.setRefreshing(false);
    }
    });

    相比RxJava,其实RxJava的方式不是更难懂吗?如果在项目中使用RxJava的方式,项目的信任学习起来成本不是会很大吗?如果用回调监听的方式,相比之下容易理解很多吧。
    a3238341c037:@张磊BaronZhang 好,我再理解理解,谢谢解答!
    张磊BARON:@海的鼻涕 如你所说,RxJava学习起来确实是有成本的,而且比较难上手。我在这个系列的第一篇文章就提到过RxJava最大的好处是就是会让代码的逻辑异常简洁,而且是随着业务逻辑的越来越复杂它任然能够保持简介。你觉得用回调会更简单一点是因为这个业务场景还不够复杂、你对RxJava也没有足够的了解。那如果业务场景更复杂一点呢?如果回调中还要嵌套回调呢?你还会觉得使用回调更简单吗?况且就我个人的理解,这个例子使用RxJava来实现代码逻辑要清晰多了。 :blush:
  • 0b4a8a69f146:你好,问下 RxJava,有给指定集合(ArrayList<String> data)添加指定数量(n)的 API吗?
    类似这样的:
    Observable.from(data)
    .API(6,new Action1() {
    @Override
    public void call(int position) {
    data.add(new SquareBean());

    }
    });
    0b4a8a69f146:@张磊BaronZhang 了解,谢谢:+1:
    张磊BARON:@Herve_Lee map scan等操作符都可以变相的实现你的需求,但你要明白的是并不是任何场景都适用RxJava的。不要为了用而用,换一种方式反而更容易实现 :)

本文标题:RxJava系列7(最佳实践)

本文链接:https://www.haomeiwen.com/subject/kflcuttx.html