RxAndroid之RxAndroidPlugins 详解

1,023 阅读2分钟

RxAndroid之RxAndroidPlugins

当我们想要调试某个程序的异步操作是否正确或者调试其他不涉及到Android库的问题时,我们并不想要去在一个Android设备上去运行程序。 如下代码,我们想要去进行同步的测试,判断我们代码的逻辑是否正确。

public final class MainPresenter { 
    // Other bits removed for brevity…
    void bind() {
        disposable.add(bookstoreModel
                          .getFavoriteBook()
                          .map(Book::getTitle)
                          .observeOn(AndroidSchedulers.mainThread())
                          .subscribe(view::setBookTitle));
    }
}

但是我们的代码中传入的AndroidSchedulers.mainThread(),而这个handler拥有的mainLooper是在ActivityThread的main方法中,调用Looper.prepareMainLooper()方法时复制的,当我们在本地计算机运行时,就会出现异常,调用Looper.getMainLooper返回的是一个null。

那么我们如何直接本地设备上去直接测试这段代码呢? RxAndroidPlugins 为我们提供了一个选择。 AndroidSchedulers.mainThread() 内部实现如下

public final class AndroidSchedulers {

    private static final class MainHolder {
        static final Scheduler DEFAULT
            = new HandlerScheduler(new Handler(Looper.getMainLooper()), true);
    }

    private static final Scheduler MAIN_THREAD =RxAndroidPlugins.initMainThreadScheduler(() -> MainHolder.DEFAULT);

    public static Scheduler mainThread() {
        return RxAndroidPlugins.onMainThreadScheduler(MAIN_THREAD);
    }
    ...
}

RxAndroidPlugins.initMainThreadScheduler 方法传入了一个Callable对象,而这个Callable调用call方法返回的对象就是拥有 mainLooper的HandlerScheduler,在一般开发中,这个 initMainThreadScheduler方法一般而言返回的就是 MainHolder.DEFAULT对象,不过,如果我们在RxAndroidPlugins进行一些操作,那么返回的就是我们制定的mainLooper 同理,RxAndroidPlugins.onMainThreadScheduler方法返回的也不一定就是传入的MAIN_THREAD。

接下来让我们详细了解下影响这两个方法返回值的三个方法。

setInitMainThreadSchedulerHandler

setInitMainThreadSchedulerHandler(Function<Callable<Scheduler>, Scheduler> handler) 该方法允许您覆盖默认的调度器实例。它接受一个延迟计算的调度器覆盖,并且结果在您第一次访问AndroidSchedulers类时被静态应用。

setMainThreadSchedulerHandler

setMainThreadSchedulerHandler(Function<Scheduler, Scheduler> handler) 这允许您提供一个二级动态覆盖的默认调度程序实例;它优先于通过setInitMainThreadSchedulerHandler提供的调度器。您还可以通过调用setInitMainThreadSchedulerHandler(null)来清除覆盖。它在每次调用androidschedul. mainthread()时计算。

reset

public static void reset() {
        setInitMainThreadSchedulerHandler(null);
        setMainThreadSchedulerHandler(null);
    }

reset方法将 mainThread和iniMainThread实例置为null了,然而,其实 setInitMainThreadSchedulerHandler(null)其实没啥作用。因为

 private static final Scheduler MAIN_THREAD =RxAndroidPlugins.initMainThreadScheduler(() -> MainHolder.DEFAULT);

MAIN_THREAD 对象的值,在第一次访问 AndroidSchedulers时 就已经被加载了。之后无论initMainThread值为何物,都不影响 MAIN_THREAD 对象。 不过reset方法对 二级覆盖是有影响的,将onMainThreadHandler值置为null,RxAndroidPlugins.onMainThreadScheduler(MAIN_THREAD);方法返回的对象就是MAIN_THREAD