文章目录
- 对于使用Rxjava过程中难免会有一些重复的代码需要封装,但我们总不能跟java一样搞个工具类,那就很尴尬了,毕竟咱今天说的是kotlin啊。那我们就得从kotlin本身的拓展方法说起了,比如我们现在要实现一个窗的工具类,因为我们常常需要在Activity中Fragment中弹Toast,java里面一般是封装一个Utils如下
public class ToastUtils {
private static Toast mToast;
public static void showToast(String content) {
if (mToast == null) {
mToast = Toast.makeText(UIUtils.getContext(), content, Toast.LENGTH_SHORT);
} else {
mToast.setText(content);
}
if (!TextUtils.isEmpty(content)) {
mToast.show();
}else{
mToast.cancel();
}
}
public static void showToastLong(String text) {
if (mToast == null) {
mToast = Toast.makeText(UIUtils.getContext(), text, Toast.LENGTH_LONG);
} else {
mToast.setText(text);
mToast.setDuration(Toast.LENGTH_LONG);
}
if (!TextUtils.isEmpty(text)) {
mToast.show();
}
}
public static void showToastCenter(String text) {
if (mToast == null) {
mToast = Toast.makeText(UIUtils.getContext(), text, Toast.LENGTH_SHORT);
mToast.setGravity(Gravity.CENTER, 0, 0);
} else {
mToast.setText(text);
}
if (!TextUtils.isEmpty(text)) {
mToast.show();
}
}
}
那在kotlin中我们肯定不能这个干了,说道拓展方法,那看Activity Fragment 就涉及到Context类,如果我们给Context类增加一个拓展方法,那我们就可以直接在里面弹窗了不是吗?
fun Context.showToast(str: String?) {
Toast.makeText(RealApplication.context,str,Toast.LENGTH_SHORT).show()
}
那我们的线程切换也是一样的
fun <T> Observable<T>.io_main(): Observable<T> {
return this.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
}
fun <T> Single<T>.io_main(): Single<T> {
return this.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
}
fun <T> Maybe<T>.io_main(): Maybe<T> {
return this.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
}
//使用的时候
Observable.interval(1000,TimeUnit.MILLISECONDS)
.io_main()
.subscribe {
showToast(it.toString())
}
线程切换就这样的完成了,用一个方法代替了两个方法,Rxjava使用最难受的其实是取消订阅,已经有了RxLifecycle,和AutoDispose框架了,但是我使用的时候就特么的别扭,能不能有一个简单的方法搞定自动取消订阅呢,如上的思想,我们能不能得到一点启示。我们分析一下,我们想要的不过是在Activity销毁的时候,取消订阅不用就可以了,先看眼别人做的吧
RxLifecycle
private static <R> Observable<R> takeUntilEvent(final Observable<R> lifecycle, final R event) {
return lifecycle.filter(new Predicate<R>() {
@Override
public boolean test(R lifecycleEvent) throws Exception {
return lifecycleEvent.equals(event);
}
});
}
@Override
public ObservableSource<T> apply(Observable<T> upstream) {
return upstream.takeUntil(observable);
}
从这两个方法中我们最起码能去分出来,那只是做了一层校验takeUntil,他这个比较完全了,意思是所有的生命周期所有,我们先实现第一步,在finish的时候取消订阅。那来吧。
//只能在Activity 中使用当Activity退出时自动取消订阅
fun <T> Observable<T>.autoDispose(activity: Activity): Observable<T> {
var dispose: Disposable? = null
return this.doOnLifecycle({
dispose = it
}, {
}).doOnNext {
//这里可以没有
if (activity == null || activity.isFinishing) {
dispose?.dispose()
}
}.filter {
//我们用filter 和takeUntil 都可以,主要就是判断当前Activity是否销毁了
if (activity == null || activity.isFinishing) {
dispose?.dispose()
}
activity != null && !activity.isFinishing
}
}
//在Activity中使用,不过是有缺陷的,你想在Presenter里面自动取消订阅,还需要把Activity实例传到 Presenter中
//但是无双全法啊。
Observable.interval(1000,TimeUnit.MILLISECONDS)
.io_main()
.autoDispose(this)
.doOnNext{
Log.i("doOnNext","")
}
.subscribe {
showToast(it.toString())
}
我们看到这里其实第一步已经实现了,在Activity销毁的时候已经不会再接收到数据了,那我们接下来要思考是就是如何在Activity其他的生命周期进行取消订阅,比如说我们到了onStop()的回调时我们就需要取消当前订阅,那我们该如何做呢,这里最困难的是我们如何知道Activity生命周期走到哪里了,我们并不想让别人继承我们的Activity那么复杂,就像如此的优雅简单。世间哪得双全法,不负如来不负卿。我们Activity生命周期总归是要有一个地方后进行监听的对不,不然搞个毛。那我想到的是我们Application.ActivityLifecycleCallbacks ,这里我们可以监听到所有activity的生命周期变换,我们只需要存起来,然后再判断的地方取出来判断就好,那我们试试。
首先,我们搞个quene来存储Activity生命周期,保证每个Activity我们用到的周期都存起来。但是后面我发现这么做听不方便的吗,试了几种方式,比如为Activity增加了一个拓展属性用来存储当前Activity 的状态,但是失败了,最终选取了一种还可以的方式,那就是利用google为我们提供的Lifecycle中获取activity状态的办法,但是必须是AppCompatActivity,通过Lifecycle获取到当前Activity的状态
//这里我们生命周期都是全部可以获取到了,那我们判断你的时候加上瞅瞅呗
fun <T> Observable<T>.autoDispose(activity: AppCompatActivity,event: Lifecycle.Event): Observable<T> {
var dispose: Disposable? = null
return this.doOnLifecycle({
dispose = it
}, {
}).doOnNext {
//这里利用android 为我们提供了生命周期的方法,但是必须是AppCompatActivity,通过Lifecycle获取到当前Activity的状态
if (activity == null || activity.lifecycle.currentState==event) {
dispose?.dispose()
}
}.filter {
if (activity == null ||activity.lifecycle.currentState==event) {
dispose?.dispose()
}
activity != null && !activity.isFinishing
}
}
到这里就搞定了今天要解决的问题,优雅的完成了任意生命周期中取消订阅。比起他们提供的这个库那个库的,本人更喜欢简单的方式吗,一句话能解决的问题就不要用两句话来说!