学习契机
接触 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> 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() {
@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 extends Observable implements Observer {
...
}
通过查看源码可以看到,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()
数据。
当我对目前这种学习方式(使用-源码分析-总结),所带来的收获沾沾自喜的时候。朋友的一番话,又警醒了我。阅读源码,只是进阶的第一步。更重要的是,对思想的掌握,站在更高的角度去思考,为什么这样设计。而不应该只满足于基础的源码分析,背后的设计思想才是精髓。
如果只是对源码进行分析,按照作者的思路去拨开云雾,得到的进步是有限的。需要再进一步的 思考,这将是我接下来需要学习的地方。