RxJava之调度器(Schedulers)

本文深入探讨了RxJava中的Scheduler,包括io、computation、immediate、newThread和trampoline等类型,并详细阐述了非阻塞I/O操作的实现。重点讨论了SubscribeOn和ObserveOn的使用,特别是observeOn在处理Android应用中的作用,同时解析了AndroidSchedulers的源码,最后介绍了默认调度器的选择与应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

       作为一个Android开发者,耳熟能详的一句话就是,Android的主线程不能做耗时操作,具体啥原因也不用多说了。  RxJava作为广泛应用的工具库,不应该没有对耗时操作的处理。对于多线程和并发编程应该有独特的理解。在之前的基础上,我们深入理解RxJava中的调度器(Schedulers)在Android开发中如何以响应式的方式创建网络操作,内存访问,以及耗时任务。

调度器(Schedulers)

    io

    Schedulers.io()调度器主要用于I/O操作,它基于根据需要,增长或缩减来自适应的线程池。大量的I/O调度操作将创建许多个线程并占用内存。一如既往的是,我们需要在性能和简捷两者之间找到一个有效的平衡点。

    computation

    Schedulers.computation()调度是精于计算工作的,它也是许多RxJava方法的默认调度器   buffer(),debounce(),delay(),interval(),sample(),skip()。

    immediate

    Schedulers.immediate()调度器主要用于立即在当前线程执行你指定的工作。它是timeout(),timeInterval(),以及timestamp()方法默认的调度器。

    newThread

    Schedulers.newThread()调度器主要用于为指定任务启动一个新的线程。

    trampoline

    Schedulers.trampoline()主要用于延迟工作任务的执行。当我们想在当前线程执行一个任务时,并不是立即,我们可以用.trampoline()将它入队。
    trampoline将会处理它的队列并且按序运行队列中每一个任务。它是repeat()和retry()方法默认的调度器。

非阻塞I/0操作的简单实现

    大家都知道I/O操作是一个耗时操作,如果在主线程进行I/O操作,必然会影响UI操作的流畅性。比如保存照片的过程中放在主线程中进行,在保存的过程中,UI是不能进行交互的。该如何处理即能保存照片又能进行UI操作?大家都会想到开一个线程,将存储操作在线程中进行,不会影响UI交互。在RxJava中,我们习惯使用io调度器进行处理。
 
<span style="font-size:14px;">  private static void blockingStoreBitmap(Context context, Bitmap bitmap, String filename) {
        FileOutputStream fOut = null;
        try {
            fOut = context.openFileOutput(filename, Context.MODE_PRIVATE);
            bitmap.compress(Bitmap.CompressFormat.PNG, 100, fOut);
            fOut.flush();
            fOut.close();
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            try {
                if (fOut != null) {
                    fOut.close();
                }
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }
    
    public static void storeBitmap(Context context, Bitmap bitmap, String filename) {
        Schedulers
            .io()
            .createWorker()
            .schedule(() -> {
                blockingStoreBitmap(context, bitmap, filename);
            });
    }</span>

    每次我们调用storeBitmap(),RxJava处理创建所有它需要从I / O线程池一个特定的I/ O线程执行保存工作,避免了UI交互阻塞。

SubscribeOn和ObserveOn    

    SubscribeOn

    SubscribeOn操作符作用于每个Observable对象,subscribeOn操作符用Scheduler来作为参数并在这个Scheduler上执行Observable调用。

   observeOn

    observeOn操作符将会在指定的调度器上返回结果,个人认为就是结果在哪个线程进行处理,比如UI子线程

    onBackpressureBuffer

    onBackpressureBuffer操作符将监管Observable何时发射数据,如果Observable比观察者接收的数据要更快的话,它必须把它们存储在缓存中并提供一个合适的时间发射数据。
    示例代码:
<span style="font-size:14px;">    private Observable<AppInfo> getApps(){
        return Observable.create(subscriber -> {
            List<AppInfoRich> apps = new ArrayList<AppInfoRich>();

            final Intent mainIntent = new Intent(Intent.ACTION_MAIN,null);
            mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);

            List<ResolveInfo> infos = getActivity().getPackageManager().queryIntentActivities(mainIntent, 0);

            for(ResolveInfo info : infos){
                apps.add(new AppInfoRich(getActivity(),info));
            }

            for (AppInfoRich appInfo:apps) {
                Bitmap icon = Utils.drawableToBitmap(appInfo.getIcon());
                String name = appInfo.getName();
                String iconPath = mFilesDir + "/" + name;
                Utils.storeBitmap(App.instance, icon,name);

                if (subscriber.isUnsubscribed()){
                    return;
                }
                subscriber.onNext(new AppInfo(name,iconPath,appInfo.getLastUpdateTime()));                
            }
            if (!subscriber.isUnsubscribed()){
                subscriber.onCompleted();
            }
        });
    }
    
    getApps()
    .onBackpressureBuffer()
    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe(new Observer<AppInfo>() { [...]}</span>
    从示例代码我们可以看出
    1.getApps是一个耗时操作,通过操作符subscribeOn使用Schedulers.io()调度器,将耗时操作在I/O线程中进行;
    2.observeOn操作符以(AndroidSchedulers.mainThread())作为参数,表明返回的结果将在UI线程中操作
    3.getApps()使用了onBackpressureBuffer操作符,主要是为了将获取到的信息缓存,在UI显示时,将数据及时发射。
    

AndroidSchedulers源码解析

<span style="font-size:14px;">    public final class AndroidSchedulers {
        private static final AndroidSchedulers INSTANCE = new AndroidSchedulers();

        private final Scheduler mainThreadScheduler;

        private AndroidSchedulers() {
            RxAndroidSchedulersHook hook = RxAndroidPlugins.getInstance().getSchedulersHook();

            Scheduler main = hook.getMainThreadScheduler();
            if (main != null) {
                mainThreadScheduler = main;
            } else {
                mainThreadScheduler = new LooperScheduler(Looper.getMainLooper());
            }
        }

        *******
    }</span>
       先纵观看下整个AndroidSchedulers实体类,AndroidSchedulers实例是以单例模式创建的,保证其唯一性,而且编译器在加载此类时,已经创建了其示例。
       再看AndroidSchedulers的构造方法,通过Scheduler main = hook.getMainThreadScheduler();其实是获取UI子线程,然后再赋值给mainThreadScheduler,我们调用时使用observeOn操作符,表明我们返回的结果应在UI子先处理
<span style="font-size:14px;">    private AndroidSchedulers() {
        RxAndroidSchedulersHook hook = RxAndroidPlugins.getInstance().getSchedulersHook();

        Scheduler main = hook.getMainThreadScheduler();
        if (main != null) {
            mainThreadScheduler = main;
        } else {
            mainThreadScheduler = new LooperScheduler(Looper.getMainLooper());
        }
    }</span>
        AndroidSchedulers定义了两个静态方法mainThread()和from(Looper looper) ,这两个方法的返回值都是Scheduler,mainThread的返回值其实AndroidSchedulers中定义的一个不可修改Scheduler的值mainThreadScheduler,表明返回结果在 UI子线程处理。这个不用多说,它的返回值应该就是AndroidSchedulers实例在创建时,mainThreadScheduler的默认值
    
<span style="font-size:14px;">  public static Scheduler from(Looper looper) {
        if (looper == null) throw new NullPointerException("looper == null");
        return new LooperScheduler(looper);
    }</span>
    从前面可以看出,AndroidSchedulers默认的处理线程可以认为UI子线程,如果返回的结果,不想在子线程处理,又该怎么处理呢?from(Looper looper)满足了我们这一意愿,通过new LooperScheduler(looper)创建调度器,实际上根据我们的实际预处理的线程中,处理返回的结果。LooperScheduler这个类其实继承了Scheduler这个抽象类。    LooperScheduler和Scheduler类涉及的内容,较多,这里不多做分析。

    

默认调度器

在RxJava中,某些Observable操作符的变体允许你设置用于操作执行的调度器,其它的则不在任何特定的调度器上执行,或者在一个指定的默认调度器上执行。下面的表格个列出了一些操作符的默认调度器:




   
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值