学习契机
接触 RxJava 有一段时间了,但总感觉对于 RxJava 的使用和理解还在入门阶段。一方面和自己没有去深入学习有关,以为使用了一些基础的操作符,就敢吹牛说自己掌握 RxJava。另一方面对RxJava 事件驱动型 的编程思想,笔者始终领悟的不好。
我认为单纯的学习操作符,实际意义不大。事实上,笔者之前也花费了大量的时间学习操作符,到头来发现效果不佳,因为我还是不知道何时,该正确的去使用 RxJava 操作符。我便向朋友请教,他说你可以试着去阅读一些 Rx 开源项目的源码,从简单的入手,去学习 Rx 带来的便利,和思维方式的改变。
又是这位朋友,向我推荐了 RxActivityResult。代码量不多,很适合我学习。下面,让我们换种方式,去 startActiviityForResult()。
简介
RxActivityResult 是 VictorAlbertos 大神的又一个 Rx 开源力作,该库不久前的更新,现已全面支持 AndroidX。当你已经受够了,从 onActivityResult() 中接受来自系统(如相机),或者自己的回调数据,不妨尝试下这个库,让你从此告别 onActivityResult()。简单介绍下这个库的特点:
- 传入
Activity或Fragment的有效实例,就可以在任何类开启一个Intent。 - 数据被封装在一个可观察的
Observable中返回,意味着可以继续享受RxJava操作符的便利。
使用
- 首先在 Project 下的
build.gradle添加maven依赖。
allprojects {
repositories {
google()
jcenter()
maven { url "https://jitpack.io" }
}
}
- 在 app 下的
build.gradle添加RxActivityResult和RxJava的依赖。
implementation 'com.github.VictorAlbertos:RxActivityResult:0.5.0-2.x'
implementation 'io.reactivex.rxjava2:rxjava:2.2.3'
- 添加完依赖,我们需要在
Application中注册RxActivityResult。
class MyApp : Application() {
override fun onCreate() {
super.onCreate()
RxActivityResult.register(this)
}
}
- 在
MainActivity中通过点击按钮,跳转至Main2Activity。以下是代码示例
@SuppressLint("CheckResult")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val intent = Intent(this, Main2Activity::class.java)
btnJump
.setOnClickListener {
RxActivityResult
.on(this)
.startIntent(intent)
.map {
it.data()
}
.subscribe {
val extra = it.getStringExtra("resultData")
println(extra)
}
}
}
- 在
Main2Activity中,点击按钮回传数据。
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main2)
btnResult.setOnClickListener {
val intent = intent
intent.putExtra("resultData", "我是回传的数据")
setResult(Activity.RESULT_OK, intent)
finish()
}
}
ok,到此一个简单的使用就完成了。如果搭配 RxBinding 使用,能够让自己的代码更加 Rx,保证这一系列操作事件流的完整性。
btnJump
.clicks()
.throttleFirst(500, TimeUnit.MILLISECONDS)
.map { Intent(this, Main2Activity::class.java) }
.flatMap {
RxActivityResult.on(this)
.startIntent(it)
}
.map{ it.data() }
.subscribe {
val stringExtra = it.getStringExtra("resultData")
println(stringExtra)
}
通过寥寥的几行代码,便告别了 onActivityResult(),并且可以接收到返回的数据。这里先抛出两个问题:
- 在
Application中为啥要注册。 onActivityResult()的具体实现是谁。
源码分析
- 首先我们看下
Application中的注册。
class MyApp:Application() {
override fun onCreate() {
super.onCreate()
RxActivityResult.register(this)
}
}
先简单介绍下 ActivityLifecycleCallbacks,它是定义在 Application 中的一个接口,可以用来监听所有 Activity 生命周期的回调,并且优先于 Activity 生命周期的回调。使用 ActivityLifecycleCallbacks 也可以判断当前 App 处于前台还是后台。具体的使用请自行查阅。
RxActivityResult.register() 其实返回的是库作者定义的 ActivitiesLifecycleCallbacks 类。通过查看源码得知,使用了传入的 Application 对象去注册监听 Activity 的生命周期。
到现在也就可以回答提出的第一个问题,在 Application 中注册 RxActivityResult,是为了可以监听到所有 Activity 的生命周期。毕竟在 onPause 之后去 startIntent() ,是没有意义的。
- 接着看下
Activity中的具体使用
RxActivityResult
.on(this) // 步骤 1
.startIntent(intent) // 步骤 2
.map { it.data }
.subscribe {
val extra = it.getStringExtra("resultData")
println(extra)
}
- 调用
on()传入的this对象,用于判断用户是从Activity或者Fragment的操作 startIntent()方法,最终会调用startHolderActivity()。
@SuppressLint("CheckResult")
private Observable<Result<T>> startHolderActivity(Request request, @Nullable OnPreResult onPreResult) {
OnResult onResult = uiTargetActivity ? onResultActivity() : onResultFragment(); // 判断从 Activity 或者 Fragment 启动的 Intent
request.setOnResult(onResult);
request.setOnPreResult(onPreResult);
// 设置请求对象
HolderActivity.setRequest(request);
// 从当前 Activity ,打开 HolderActivity
activitiesLifecycle.getOLiveActivity().subscribe(new Consumer<Activity>() {
@Override
public void accept(Activity activity) throws Exception {
activity.startActivity(new Intent(activity, HolderActivity.class)
.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION));
}
});
// 返回 PublishSubject
return subject;
}
先看下 onResultActivity()
private OnResult onResultActivity() {
return new OnResult() {
@Override
public void response(int requestCode, int resultCode, Intent data) {
if (activitiesLifecycle.getLiveActivity() == null) return;
//If true it means some other activity has been stacked as a secondary process.
//Wait until the current activity be the target activity
if (activitiesLifecycle.getLiveActivity().getClass() != clazz) {
return;
}
T activity = (T) activitiesLifecycle.getLiveActivity();
// 发射 Result 结果
subject.onNext(new Result<>(activity, requestCode, resultCode, data));
subject.onComplete();
}
@Override
public void error(Throwable throwable) {
subject.onError(throwable);
}
};
}
创建一个 OnResult 对象,并且在 response() 中发射 Result 结果。
- Subject
Subject既可以是数据源Observable,也可以是数据的订阅者Observer。
public abstract class Subject<T> extends Observable<T> implements Observer<T> {
...
}
通过查看源码可以看到,Subject 实际上还是 Observable,只不过它实现了 Observer接口,可以通过 onNext、onComplete、onError 方法发射和终止发射数据。作者在发射 Result 的时候,使用了 PublischSubject,PublischSubject 的特点是: Observer 只接受被订阅之后发射的数据。
- 看下
HolderActivity中的操作
-
在
onCreate()中打开真正的Intent对象 -
在
onActivityResult中关闭HolderActivity,并且在onDestroy回传数据
@Override
protected void onDestroy() {
super.onDestroy();
if (onResult != null)
onResult.response(requestCode, resultCode, data);
}
总结下大体的逻辑,好比我们购物的流程,从京东下单买书 (startActivityForResult),店主交待员工小王(HoldrActivity)去仓库查找书籍,并打包发送快递(PublischSubject.onNext(Result()))。快递员送货上门,顾客核对购买的信息(intent.getStringExtra("resultData")),信息无误的话获取购买的书籍。
总结与思考
通过对 RxActivityResult 库的简单分析,了解了 ActivityLifecycleCallbacks 和 PublischSubject 在三方库中的具体使用。也认识了一些 RxJava 的操作符,如 takeWhile 过滤操作符。更重要的是,在没有遇见 RxActivityResult 时,笔者通常都是按部就班的在 onActivityResult() 中获取数据,而作者的这种方式,打破了我之前的认识,原来还可以这样处理 onActivityResult() 数据。
当我对目前这种学习方式(使用-源码分析-总结),所带来的收获沾沾自喜的时候。朋友的一番话,又警醒了我。阅读源码,只是进阶的第一步。更重要的是,对思想的掌握,站在更高的角度去思考,为什么这样设计。而不应该只满足于基础的源码分析,背后的设计思想才是精髓。
如果只是对源码进行分析,按照作者的思路去拨开云雾,得到的进步是有限的。需要再进一步的 思考,这将是我接下来需要学习的地方。