彻底搞清楚 RxJava 是什么东西
其实从rxjava14年出现到现在,我是去年从一个朋友那里听到的,特别是随着现在app项目越来越大,分层越来越不明确的情况下,rxjava出现了,以至于出现了rxandroid。其实如果你了解观察者模式的话,rxjava并没有你说的那么神秘。再次,我对rxjava并不崇拜,我的原则是怎么写代码简单,代码结构清晰,维护简单,就是好框架。
讲rxjava之前首先说一下Android mvp开发模式。
MVP的工作流程
- Presenter负责逻辑的处理,
- Model提供数据,
- View负责显示。 
 作为一种新的模式,在MVP中View并不直接使用Model,它们之间的通信是通过Presenter来进行的,所有的交互都发生在Presenter内部,而在MVC中View会从直接Model中读取数据而不是通过 Controller。
接下来说说rxjava
- RxJava 到底是什么
- RxJava 好在哪
- API 介绍和原理简析
- RxJava 的适用场景和使用方式
- 最后
如果你要了解rxjava是什么,由来,以及作用和原理,请点击上面的链接。
针对上面的问题,我们简单的了解下一些基本的概念。
什么是rxJava
rxJava的好处
Android 创造的
AsyncTask 和Handler ,其实都是为了让异步代码更加简洁。RxJava的优势也是简洁,但它的简洁的与众不同之处在于,随着程序逻辑变得越来越复杂,它依然能够保持简洁。
看下rxjava的例子
rxjava原理简析
Observer )和被观察者(Observable )。观察者通过将被观察的对象加到自己的观察队列中,当被观察者发生改变时,就会通知观察者东西已经改变。
Observable (可观察者,即被观察者)、 Observer (观察者)、 subscribe (订阅)、事件。Observable 和Observer 通过 subscribe() 方法实现订阅关系,从而 Observable 可以在需要的时候发出事件来通知 Observer数据刷新。RxJava 的事件回调方法除了普通事件
onNext() (相当于 onClick() / onEvent())之外,还定义了两个特殊的事件:onCompleted()onError()。- onCompleted():
 事件队列完结。RxJava 不仅把每个事件单独处理,还会把它们看做一个队列。RxJava 规定,当不会再有新的- onNext()发出时,需要触发- onCompleted()方法作为标志。
- onError(): 事件队列异常。在事件处理过程中出异常时,- onError()会被触发,同时队列自动终止,不允许再有事件发出。
注意:在一个正确运行的事件序列中, onCompleted() 和 onError() 有且只有一个,也就是说onCompleted() 和 onError() 二者也是互斥的。在响应的队列中只能调用一个。
1) 创建 Observer(被观察者对象)
//Observable部分,被观察者部分
        Observable<String> myObservable=Observable.create(new Observable.OnSubscribe<String>() {
            @Override
            public void call(Subscriber<? super String> subscriber) {
                subscriber.onNext("我是被观察的对象");
                subscriber.onCompleted();
            }
        });
2) 创建Subscriber(观察者对象)
 //Subscriber部分,观察者部分
        Subscriber<String> mySubscriber=new Subscriber<String>() {
            @Override
            public void onCompleted() {
            }
            @Override
            public void onError(Throwable e) {
            }
            @Override
            public void onNext(String s) {
                text.setText(s);
            }
        };
3) Observer和Subscriber关联
myObservable.subscribe(mySubscriber);
这样就完成了一个简单的rxjava,是不是很简单。
除了 subscribe(Observer) 和 subscribe(Subscriber) ,subscribe() 还支持不完整定义的回调,RxJava
 会自动根据定义创建出Subscriber 。
Observable.just("Hello, world!")
    .subscribe(new Action1<String>() {
        @Override
        public void call(String s) {
              System.out.println(s);
        }
    });  
使用java8的lambda可以使代码更简洁
Observable.just("Hello, world!")
    .subscribe(s -> System.out.println(s));  
然而如果你认为rxjava只有这个用处,那么也什么牛逼的,在 RxJava 的默认规则中,事件的发出和消费都是在同一个线程的。观察者模式本身的目的就是『后台处理,前台回调』的异步机制,因此异步对于
 RxJava 是至关重要的。而要实现异步,则需要用到 RxJava 的另一个概念: Scheduler 。
Scheduler (线程调度器)
线程控制与调度
subscribe(),就在哪个线程生产事件;在哪个线程生产事件,就在哪个线程消费事件。而如果要实现线程的调度,就需要scheduler(线程调度器)。已经内置了几个
Scheduler ,它们已经适合大多数的使用场景:- Schedulers.immediate():
 直接在当前线程运行,相当于不指定线程。这是默认的- Scheduler。
- Schedulers.newThread():
 总是启用新线程,并在新线程执行操作。
- Schedulers.io(): I/O
 操作(读写文件、读写数据库、网络信息交互等)所使用的- Scheduler。行为模式和- newThread()差不多,区别在于- io()的内部实现是是用一个无数量上限的线程池,可以重用空闲的线程,因此多数情况下- io()比- newThread()更有效率。不要把计算工作放在- io()中,可以避免创建不必要的线程。
- Schedulers.computation():
 计算所使用的- Scheduler。这个计算指的是 CPU 密集型计算,即不会被 I/O 等操作限制性能的操作,例如图形的计算。这个- Scheduler使用的固定的线程池,大小为
 CPU 核数。不要把 I/O 操作放在- computation()中,否则 I/O 操作的等待时间会浪费 CPU。
- 另外, Android 还有一个专用的 AndroidSchedulers.mainThread(),它指定的操作将在
 Android 主线程运行。
Sceeduler默认给我们提供了subscribeOn() 和 observeOn() 两个方法来对线程进行控制 。
Observable.just(1, 2, 3, 4)
                .subscribeOn(Schedulers.io()) // 指定 subscribe() 发生在 IO 线程
                .observeOn(AndroidSchedulers.mainThread()) // 指定 Subscriber 的回调发生在主线程
                .subscribe(new Action1<Integer>() {
                    @Override
                    public void call(Integer number) {
                    }
                });
上面这段代码中,由于 subscribeOn(Schedulers.io()) 的指定,被创建的事件的内容 1、2、3、4 将会在
 IO 线程发出;而由于
observeOn(AndroidScheculers.mainThread())的指定,因此
subscriber 数字的打印将发生在主线程。事实上,这种在
subscribe() subscribeOn(Scheduler.io()) 和 observeOn(AndroidSchedulers.mainThread()) 的使用方式非常常见,int drawableRes = ...;
ImageView imageView = ...;
Observable.create(new OnSubscribe<Drawable>() {
    @Override
    public void call(Subscriber<? super Drawable> subscriber) {
        Drawable drawable = getTheme().getDrawable(drawableRes));
        subscriber.onNext(drawable);
        subscriber.onCompleted();
    }
})
.subscribeOn(Schedulers.io()) // 指定 subscribe() 发生在 IO 线程
.observeOn(AndroidSchedulers.mainThread()) // 指定 Subscriber 的回调发生在主线程
.subscribe(new Observer<Drawable>() {
    @Override
    public void onNext(Drawable drawable) {
        imageView.setImageDrawable(drawable);
    }
    @Override
    public void onCompleted() {
    }
    @Override
    public void onError(Throwable e) {
        Toast.makeText(activity, "Error!", Toast.LENGTH_SHORT).show();
    }
});
这样,加载图片发生在UI线程,而设置显示放到子线程出来,这样就不会出现卡顿。
变换
Observable.just("images/logo.png") // 输入类型 String
    .map(new Func1<String, Bitmap>() {
        @Override
        public Bitmap call(String filePath) { // 参数类型 String
            return getBitmapFromPath(filePath); // 返回类型 Bitmap
        }
    })
    .subscribe(new Action1<Bitmap>() {
        @Override
        public void call(Bitmap bitmap) { // 参数类型 Bitmap
            showBitmap(bitmap);
        }
    });
这里出现了一个 Func1 的类。它和 Action1 非常相似,也是
 RxJava 的一个接口,用于包装含有一个参数的方法。 Func1 和 Action的区别在于, Func1 包装的是有返回值的方法。FuncX 和ActionX 的区别在 FuncX 包装的是有返回值的方法。
通过上面的代码我们看到:map() 方法将参数中的 String 对象转换成一个 Bitmap 对象后返回,而在经过 map() 方法后,事件的参数类型也由 String转为了 Bitmap。这就是最长久的转换。
map():
 事件对象的直接变换示意图:

flatMap():
 这是一个很有用但非常难理解的变换
首先假设这么一种需求:假设有一个数据结构『学生』,现在需要打印出一组学生的属性(我选择属性,是因为如果对象可以打印,你们单个属性肯定不是问题)。
Student[] students = ...;
Subscriber<Student> subscriber = new Subscriber<Student>() {
    @Override
    public void onNext(Student student) {
        List<Course> courses = student.getCourses();
        for (int i = 0; i < courses.size(); i++) {
            Course course = courses.get(i);
            Log.d(tag, course.getName());
        }
    }
    ...
};
Observable.from(students)
    .subscribe(subscriber);
写法也很简单,看得也很明白。
变换的原理:lift()
RxJava 的内部,它们是基于同一个基础的变换方法:
lift(Operator)。首先看一下 lift() 的内部实现(仅核心代码):// 注意:这不是 lift() 的源码,而是将源码中与性能、兼容性、扩展性有关的代码剔除后的核心代码。
// 如果需要看源码,可以去 RxJava 的 GitHub 仓库下载。
public <R> Observable<R> lift(Operator<? extends R, ? super T> operator) {
    return Observable.create(new OnSubscribe<R>() {
        @Override
        public void call(Subscriber subscriber) {
            Subscriber newSubscriber = operator.call(subscriber);
            newSubscriber.onStart();
            onSubscribe.call(newSubscriber);
        }
    });
}
彻底搞清楚 RxJava 是什么东西的更多相关文章
- 关于 RxJava  技术介绍
		Awesome-RxJava RxJava resources Blog 给 Android 开发者的 RxJava 详解 -强烈推荐 扔物线的文章 讲解非常详细 NotRxJava懒人专用指南 -这 ... 
- 一个在 Java VM 上使用可观测的序列来组成异步的、基于事件的程序的库 RxJava,相当好
		https://github.com/ReactiveX/RxJava https://github.com/ReactiveX/RxAndroid RX (Reactive Extensions,响 ... 
- CMMI 是什么东西?
		摘要: CMMI全称是Capability Maturity Model Integration,CMMI是个好东西来的,但行内人士对她的认识并不全面,甚至有种种的误解.尽管网上有很多CMM ... 
- 我的Android进阶之旅------>RxJava学习资料汇总
		在响应式编程中,应该牢记以下两点: everything is a stream(一切皆流) don't break the chain(不要打断链式结构) 记住,可观测序列就像一条河,它们是流动的. ... 
- RxJava 参考文档
		/*************************************************************** * RxJava 参考文档 * 说明: * 最近无意中发现RxJava ... 
- 5分钟搞定android混淆(转)
		转自:https://www.jianshu.com/p/f3455ecaa56e 前言 混淆是上线前挺重要的一个环节.android使用的ProGuard,可以起到压缩,混淆,预检,优化的作用.但是 ... 
- PE Checksum Algorithm的较简实现
		这篇BLOG是我很早以前写的,因为现在搬移到CNBLOGS了,经过整理后重新发出来. 工作之前的几年一直都在搞计算机安全/病毒相关的东西(纯学习,不作恶),其中PE文件格式是必须知识.有些PE文件,比 ... 
- ASP.NET 5 Target framework dnx451 and dnxcore50
		中文不知如何定义标题,所以干脆就直接贴出关键字,在 ASP.NET 5 项目的 project.json 配置文件中,会有这样的定义: "frameworks": { " ... 
- 移动端web开发——视口
		本篇主要是记录一下移动端视口的分类说明和其它的一些知识.在开始之前,先看一个典型的例子: <meta name="viewport" content="width= ... 
随机推荐
- SQL Server AlwaysON从入门到进阶(3)——基础架构
			本文属于SQL Server AlwaysON从入门到进阶系列文章 前言: 本文将更加深入地讲解WSFC所需的核心组件.由于AlwaysOn和FCI都需要基于WSFC之上,因此我们首先要了解在Wind ... 
- 安卓开发遇到Error:Execution failed for task ':app:transformClassesWithDexForDebug'.
			问题如下: Error:Execution failed for task ':app:transformClassesWithDexForDebug'. com.android.build.api. ... 
- Python 继承标准类时发生了什么
			定义标准类dict的一个子类c: >>> class c(dict): pass >>> y=c({1:2,3:4}) >>> y {1: 2, ... 
- JVM概述
			JVM是什么 JVM全称是Java Virtual Machine(java虚拟机).它之所以被称之为是"虚拟"的,就是因为它仅仅是由一个规范来定义的抽象计算机.我们平时经常使用的 ... 
- Dynamics CRM   FORM脚本库加载本地脚本
			用传统的开发方式,js脚本都是保存在数据库中的,这样也方便迁移,但如果不想存数据库而是存在物理磁盘上,则可通过下述代码,将脚本存放在CRMWEB文件夹的某个路径下,每次都动态引用本地JS. funct ... 
- Android播放在线音乐文件
			Android播放在线音频文件 效果图: 源码下载地址: http://download.csdn.net/detail/q4878802/9020687 添加网络权限: <uses-permi ... 
- 【NPR】卡通渲染
			写在前面 我的博客讲过好几篇卡通渲染了,比如[Unity Shader实战]卡通风格的Shader(一).[Unity Shader实战]卡通风格的Shader(二).[NPR]漫谈轮廓线的渲染.[S ... 
- 2.5、Android Studio添加多适配的向量图片
			Android Studio包含一个Vector Asset Studio的工具,可以帮助你添加Material图标和导入SVG(Scalable Vector Graphic)文件到你的项目中作为向 ... 
- linux shell 判断文件是否存在等符号
			-a file exists. -b file exists and is a block special file. -c file exists and is a character spec ... 
- Coroutine协同程序介绍(Unity3D开发之三)
			猴子原创,欢迎转载.转载请注明: 转载自Cocos2D开发网–Cocos2Dev.com,谢谢! 原文地址: http://www.cocos2dev.com/?p=496 Coroutine在Uni ... 
