赞
踩
今晚摔杯为号!(李家)
rxjava有很多强大的操作符,前面几篇我们其实已经介绍了map转换操作符的实战用法,今天来看看一个更牛逼的flatMap操作符。小老板,多捞哦。
其实我个人认为rxjava最牛逼的地方在于,它很轻易的解决了Android中比较棘手的一个问题,那就是线程切换。在Android的编码过程中,我们切换线程一般都是开启子线程,然后在子线程中调用runOnMain或者利用handler,或者说利用AsnycTask等(多说一句,其实最后底层都是利用的handler),真的是比较麻烦的。但是在rxjava中就很容易了,而且提供了逻辑清晰的链式编程范式。
在上述我们的需求中,我们需要把一张秀色可餐的美女图片保存到相册中。
这其中包含了三个操作:
按照正常的方式虽然第一步我们用glide就可以轻易完成,但是后面两个步骤同样需要进行很麻烦的切换线程,我&*&%#@。不多说,懂得兄弟自然都懂。接下来用rxjava来实现,如下:
第一步:
Observable.create(new ObservableOnSubscribe<Bitmap>()
{
@Override
public void subscribe(ObservableEmitter<Bitmap> e) throws Exception
{
Bitmap bitmap = Glide.with(mContext).asBitmap().load(imgUrl).submit().get();
if (bitmap == null)
{
e.onError(new Exception("无法下载图片"));
}
e.onNext(bitmap);
e.onComplete();
}
}).subscribeOn(Schedulers.io());
onNext发射的是一个bitmap,注意我们最后需要的是一个Uri from a file。所以我们需要转换
第二步:
.flatMap(new Function<Bitmap, ObservableSource<Uri>>()
{
@Override
public ObservableSource<Uri> apply(Bitmap bitmap) throws Exception
{
File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getPath(),
"http_exception");
if (!file.exists())
{
file.mkdir();
}
String fileName = "meizi.jpg";
imgFile = new File(file, fileName);
FileOutputStream fileOutputStream = new FileOutputStream(imgFile);
assert bitmap != null;
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fileOutputStream);
fileOutputStream.flush();
fileOutputStream.close();
Uri uri = Uri.fromFile(imgFile);
// 通知图库更新
Intent scannerIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, uri);
mContext.sendBroadcast(scannerIntent);
//最后发射一个uri单项
return Observable.just(uri);
}
}).subscribeOn(Schedulers.io())//连起来调用后,此指定线程只需要指定一次
第三步:
.observeOn(AndroidSchedulers.mainThread())//切换到主线程,大胸弟,你说切换线程方不方便。
.subscribe(new Consumer<Uri>()
{
@Override
public void accept(Uri uri) throws Exception
{
String msg = String.format("图片已保存至 %s 文件夹", imgFile.getAbsoluteFile());
Toast.makeText(mContext, msg, Toast.LENGTH_SHORT).show();
}
}, new Consumer<Throwable>()
{
@Override
public void accept(Throwable throwable) throws Exception
{
Toast.makeText(mContext, throwable.getMessage(), Toast.LENGTH_SHORT).show();
}
});
有没有懂的兄弟? rxjava的线程切换机制和链式编程范式是多么多么的强大。那有没有人想知道flatMap的转换流程内部是怎么执行的呢? 我以前用着的时候就觉得挺爽,用多之后就感觉一定要弄清楚代码在rxjava中是怎么走的,下面介绍一下flatMap的源码。
开局一张图,过程全靠编!
看图之前记住这几个点:
然后记住几个Observable中的源码方法:
create方法:
@SchedulerSupport(SchedulerSupport.NONE)
public static <T> Observable<T> create(ObservableOnSubscribe<T> source) {
ObjectHelper.requireNonNull(source, "source is null");
return RxJavaPlugins.onAssembly(new ObservableCreate<T>(source));
}
flatMap方法:
@SchedulerSupport(SchedulerSupport.NONE)
public final <R> Observable<R> flatMap(Function<? super T, ? extends ObservableSource<? extends R>> mapper) {
return flatMap(mapper, false);
}
//最后调用到
@SchedulerSupport(SchedulerSupport.NONE)
public final <R> Observable<R> flatMap(Function<? super T, ? extends ObservableSource<? extends R>> mapper,
boolean delayErrors, int maxConcurrency, int bufferSize) {
//省略大段代码,可以看到返回的是ObservableFlatMap对象
return RxJavaPlugins.onAssembly(new ObservableFlatMap<T, R>(this, mapper, delayErrors, maxConcurrency, bufferSize));
}
subscribe方法:
@SchedulerSupport(SchedulerSupport.NONE)
public final Disposable subscribe(Consumer<? super T> onNext, Consumer<? super Throwable> onError) {
return subscribe(onNext, onError, Functions.EMPTY_ACTION, Functions.emptyConsumer());
}
//一直往下调用,直到下面这个
@Override
public final void subscribe(Observer<? super T> observer) {
ObjectHelper.requireNonNull(observer, "observer is null");
try {
//省略大段代码,可以认为调用subscribe方法最终都会调用被观察者Observable自己的
//subscribeActual方法, 而这个方法是抽象的方法, 需要各个实现类去实现。
subscribeActual(observer);
} catch (NullPointerException e) { // NOPMD
throw e;
} catch (Throwable e) {
}
}
有时候吧,看一些大神博客能学到很多知识。但用多了之后,我总有一种不安全感,我很多时候在想这种不安全感是什么呢? 后来我想明白了,这种不安全感就是我只知道用它,而不知道为什么我们可以这么用。
Github:Demo
以上。
上篇博客:App架构设计实战一:初步引入MVP
下篇博客:App实战:动态申请权限以及为所欲为之终极扩展
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。