系列文章
RxJava系列之简介和观察者设计模式
RxJava系列之上游与下游
RxJava系列之常用创建型操作符
RxJava系列之常用变换操作符
RxJava系列之常用过滤操作符
RxJava系列之常用条件操作符
RxJava系列之常用合并操作符
RxJava系列之常用异常操作符
RxJava系列之线程切换实战
RxJava系列之背压模式
RxJava系列之配合Retrofit
RxJava系列之泛型高级
RxJava系列之手写create操作符
RxJava系列之手写create操作符增加泛型限定
RxJava系列之手写just操作符
RxJava系列之手写map操作符
RxJava系列之手写切换线程
切换线程
在上游和下游之间增加切换线程的操作,如果手写map操作符明白的话, 这里就很简单。
使上游执行在子线程的ObservableOnSubscribe的子类
// 上游处理 异步线程的 Observable的子类 [给所有上游 切换异步线程]
public class ObservableOnIO<T> implements ObservableOnSubscribe<T>{
// 线程池
private final static ExecutorService EXECUTOR_SERVICE = Executors.newCachedThreadPool();
// 拿到上一层
private ObservableOnSubscribe<T> source;
public ObservableOnIO(ObservableOnSubscribe<T> source) {
this.source = source;
}
@Override
public void subscribe(final Observer<? super T> observableEmitter) {
// source.subscribe(observableEmitter); // 是主线程
// 用线程池的目的,是为了让 所有上游 全部都在 线程池中 异步运行
EXECUTOR_SERVICE.submit(new Runnable() {
@Override
public void run() {
source.subscribe(observableEmitter); // 线程池里面所执行的了
}
});
}
}
就是在调用上游的source.subscribe方法的时候,放在子线程执行。
使下游执行在主线程的ObservableOnSubscribe的子类
// [给所有下游 切换Android主线程线程]
public class ObserverAndroidMain_On<T> implements ObservableOnSubscribe<T>{
// 拿到上一层
private ObservableOnSubscribe<T> source;
public ObserverAndroidMain_On(ObservableOnSubscribe<T> source) {
this.source = source;
}
@Override
public void subscribe(Observer<? super T> observableEmitter) { // == Observer
// 包裹是为了,往下执行的时候,优先执行我们的 包裹
PackageObserver<T> packageObserver = new PackageObserver(observableEmitter);
// 把包裹交给source
source.subscribe(packageObserver);
}
// 包裹一层 Observer
private final class PackageObserver<T> implements Observer<T> {
// 拿到上一层
// private ObservableOnSubscribe<T> source;
// 拥有下一层的能力
// private Function<T, R> function; // 不用读写模式
private Observer<T> observer; // 临时存储一份
public PackageObserver(Observer<T> observer) {
// this.source = source;
// this.function = function;
this.observer = observer;
}
@Override
public void onSubscribe() {}
@Override
public void onNext(final T item) {
// Handler
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
// 变成 Android main线程
observer.onNext(item);
}
});
}
@Override
public void onError(final Throwable e) {
// Handler
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
// 变成 Android main线程
observer.onError(e);
}
});
}
@Override
public void onComplete() {
// Handler
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
// 变成 Android main线程
observer.onComplete();
}
});
}
}
}
在接收到上游事件的时候,发射到下游之前,先切换到主线程。这样下游的所有事件都是在主线程接收到了。
测试代码
// todo 打印 上游 下游 线程
public void test2(View view) {
// 最顶端
Observable.create(new ObservableOnSubscribe<Integer>() {
@Override
public void subscribe(Observer<? super Integer> observableEmitter) {
Log.d(TAG, "上游 subscribe: --- " + Thread.currentThread().getName());
observableEmitter.onNext(1);
}
})
.map(new Function<Integer, String>() {
@Override
public String apply(Integer integer) {
Log.d(TAG, "map 1 --- " + Thread.currentThread().getName());
return integer + ">>>";
}
})
.map(new Function<String, String>() {
@Override
public String apply(String s) {
Log.d(TAG, "map 2 --- " + Thread.currentThread().getName());
return s + "???";
}
})
// 给上游分配异步线程
.observables_On()
// 给下游分配Android主线程
// new Observable<T>(下游分配异步线程 == ObservableOnIO).xxx
.observers_AndroidMain_On()
// main线程.订阅
// new Observable<T>(下游分配Android主线程 == ObserverAndroidMain_On).订阅
.subscribe(new Observer<String>() {
@Override
public void onSubscribe() {
}
@Override
public void onNext(String item) {
Log.d(TAG, "下游 onNext: --- " + Thread.currentThread().getName());
}
@Override
public void onError(Throwable e) {
}
@Override
public void onComplete() {
}
});
}
使用手写的RxJava加载网路图片
// todo 用我们自己写的RxJava下载图片 异步下载 线程切换 更新UI
public void test3(View view) {
final String PATH = "http://img.redocn.com/sheying/20140731/qinghaihuyuanjing_2820969.jpg";
Observable.just(PATH)
.map(new Function<String, Bitmap>() {
@Override
public Bitmap apply(String s) {
try {
Thread.sleep(2000);
URL url = new URL(PATH);
HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
httpURLConnection.setConnectTimeout(5000);
int code = httpURLConnection.getResponseCode();
if (code == HttpURLConnection.HTTP_OK) {
InputStream inputStream = httpURLConnection.getInputStream();
Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
return bitmap;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
// 关闭流 系统资源
}
return null;
}
})
// 给图片加水印
.map(new Function<Bitmap, Bitmap>() {
@Override
public Bitmap apply(Bitmap bitmap) {
Paint paint = new Paint();
paint.setColor(Color.RED);
paint.setTextSize(80);
return drawTextToBitmap(bitmap, "RxJava直播课 手写线程切换", paint, 80, 80);
}
})
// 给上游分配异步线程 下载图片
.observables_On()
// 给下游分配主线程 更新UI
.observers_AndroidMain_On()
.subscribe(new Observer<Bitmap>() {
@Override
public void onSubscribe() {
progressDialog = new ProgressDialog(MainActivity.this);
progressDialog.setMessage("正在下载中...");
progressDialog.show();
}
@Override
public void onNext(Bitmap item) {
imageView.setImageBitmap(item);
}
@Override
public void onError(Throwable e) {
}
@Override
public void onComplete() {
if (progressDialog != null) progressDialog.dismiss();
}
});
}
//图片上绘制文字
private Bitmap drawTextToBitmap(Bitmap bitmap, String text, Paint paint, int paddingLeft, int paddingTop) {
Bitmap.Config bitmapConfig = bitmap.getConfig();
paint.setDither(true); // 获取跟清晰的图像采样
paint.setFilterBitmap(true);// 过滤一些
if (bitmapConfig == null) {
bitmapConfig = Bitmap.Config.ARGB_8888;
}
bitmap = bitmap.copy(bitmapConfig, true);
Canvas canvas = new Canvas(bitmap);
canvas.drawText(text, paddingLeft, paddingTop, paint);
return bitmap;
}
总结
切换线程和map变换操作符很类似,都是拦截了上下游之间的直接引用,从而在中间做处理。如果这里看不明白,可以到手写map变换操作符中仔细学习。