kotlin中Rxjava如何在Activity中优雅的自动取消订阅以及线程切换

文章目录

  1. 对于使用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
    }
}

到这里就搞定了今天要解决的问题,优雅的完成了任意生命周期中取消订阅。比起他们提供的这个库那个库的,本人更喜欢简单的方式吗,一句话能解决的问题就不要用两句话来说!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值