RxAndroid从零开始学之三(线程调度)

通过前面的文章,我们已经知道了RxAndroid中的Observable、Subscribers、Observer的创建,及subscribe的使用。
接下来,我们开始学习RxAndroid中的线程。

线程

学Android中恐怕无人不知ANR.正因为如此,我们才会使用Thread+Handler或者Aysnctask的代码编写方式。

假设有这么一个需求,程序要进行一个耗时的计算任务,然后得到一个字符串,再显示在界面上的TextView上。用传统方式如下:

new Thread(new Runnable() {
    @Override
    public void run() {
       try {
          Thread.sleep(9000);
        } catch (InterruptedException e) {
          e.printStackTrace();
        }

        runOnUiThread(new Runnable() {
           @Override
           public void run() {
             mTvMsg.setText("找到一个好朋友");
           }
       });
    }
  }).start();

在一个Thread中执行耗时任务,然后通过Handler或者runOnUiThread()方法进行ui操作。
代码是比较简单,但太烦琐。后来,Android改进了引入了AyncTask的概念。

class TestTask extends AsyncTask<Void,Void,String>{

    @Override
    protected String doInBackground(Void... params) {
        try {
            Thread.sleep(9000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "AsyncTask 找到一个好朋友";
    }

    @Override
    protected void onPostExecute(String s) {
        super.onPostExecute(s);
        mTvMsg.setText(s);
    }
 }

@OnClick(R.id.btn_test_aynctask)
public void testAyncTask(){
    TestTask task = new TestTask();
    task.execute();
}

代码简洁了很多,很长一段时间,我们都是以这样的方式编写代码。
但现在我们多了一种选择,那就是RxAndroid。
我们可以这样写。

Observable.create(new Observable.OnSubscribe<String>() {
    @Override
    public void call(Subscriber<? super String> subscriber) {
        try {
            Thread.sleep(9000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        subscriber.onNext("RxAndroid 找到一个好朋友");
    }
    }).subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())//Android 特有的Thread
    .subscribe(new Action1<String>() {
        @Override
        public void call(String s) {
            mTvMsg.setText(s);
        }
});

说实话,我去年刚接触这个的时候,我在想,这代码也不见得少啊,整天整这些莫名其妙的框架,然后多了很多新概念,有个x用。很多年前,对于mvp模式我也是这样想的。对于一些hello word型的小demo,我干嘛用这么复杂的东西呢?

给自己添堵吗?

但是后来,代码写多了,代码越来越复杂了,如果所有的东西都要自己撸一遍亲自实现,人会整崩溃的,我经常抱着学习的态度去对待项目工程,但有时候边学边写的进度是慢了一点,所以嘛,找个开源的比较可靠的框架应用到项目工程中,可以让自己开发速度加快。
当初java语言创立者就说要让程序员写代码像喝咖啡一样轻松,所以才让java语言以咖啡产地爪哇岛为名。
而RxAndroid也是这样的一个异步框架,让开发者不再疲于应付多线程异步之间的处理关系。让更多精力。

RxAndroid中线程的处理不在于代码少了多少,而是在于代码结构清楚了不少。这个是很重要的。这个跟mvp模式还真像。

我们看到,从Observable、Subscriber的创建,再到两者之间的subscribe,这就是一条链式的调用,整个事件流程比较清晰,况且Observable的创建,和Subscriber中被观察的地方都可以指定线程,显而易见,广大Android开发者都会喜欢这样的事情,如果可以谁愿意,不厌其烦去写Thread+Handler或者AsyncTask呢?

Schedulers

我们在上一节代码中已经见到过Schedulers.io()这样的形式,它用来调度线程的切换。
它的代码不长,方法上都有比较详细的注释。我们可以看看,代码如下:


//代码有删简

/**
 * Static factory methods for creating Schedulers.
 */
public final class Schedulers {

    private final Scheduler computationScheduler;
    private final Scheduler ioScheduler;
    private final Scheduler newThreadScheduler;

    private static final Schedulers INSTANCE = new Schedulers();

    private Schedulers() {

        Scheduler c = RxJavaPlugins.getInstance().getSchedulersHook().getComputationScheduler();
        if (c != null) {
            computationScheduler = c;
        } else {
            computationScheduler = new EventLoopsScheduler();
        }

        Scheduler io = RxJavaPlugins.getInstance().getSchedulersHook().getIOScheduler();
        if (io != null) {
            ioScheduler = io;
        } else {
            ioScheduler = new CachedThreadScheduler();
        }

        Scheduler nt = RxJavaPlugins.getInstance().getSchedulersHook().getNewThreadScheduler();
        if (nt != null) {
            newThreadScheduler = nt;
        } else {
            newThreadScheduler = NewThreadScheduler.instance();
        }
    }

    public static Scheduler immediate() {
        return ImmediateScheduler.instance();
    }


    public static Scheduler newThread() {
        return INSTANCE.newThreadScheduler;
}

    public static Scheduler computation() {
        return INSTANCE.computationScheduler;
    }

    public static Scheduler io() {
        return INSTANCE.ioScheduler;
    }

代码的注释说明Schedulers是一个静态工厂方法类,用来产生各种类型的Scheduler。而且它是单例模式。
Schedulers内部有三个私有的Scheduler变量computationScheduler、ioScheduler、newThreadScheduler。它们分别通过computation()、io()和newThread()暴露。

Schedulers.computation()
/**
     * Creates and returns a {@link Scheduler} intended for computational work.
     * <p>
     * This can be used for event-loops, processing callbacks and other computational work.
     * <p>
     * Do not perform IO-bound work on this scheduler. Use {@link #io()} instead.
     * <p>
     * Unhandled errors will be delivered to the scheduler Thread's {@link java.lang.Thread.UncaughtExceptionHandler}.
     *
     * @return a {@link Scheduler} meant for computation-bound work
     */
    public static Scheduler computation() {
        return INSTANCE.computationScheduler;
    }

代码注释说这是一个计算时用的Scheduler,这里的计算跟cpu相关,主要用于图形计算或者是数据计算,代码特别提到不要在这个线程做与io相关的工作,要用io()代替。

Scheduler.io()
/**
     * Creates and returns a {@link Scheduler} intended for IO-bound work.
     * <p>
     * The implementation is backed by an {@link Executor} thread-pool that will grow as needed.
     * <p>
     * This can be used for asynchronously performing blocking IO.
     * <p>
     * Do not perform computational work on this scheduler. Use {@link #computation()} instead.
     * <p>
     * Unhandled errors will be delivered to the scheduler Thread's {@link java.lang.Thread.UncaughtExceptionHandler}.
     *
     * @return a {@link Scheduler} meant for IO-bound work
     */
    public static Scheduler io() {
        return INSTANCE.ioScheduler;
    }

注释中说明了此方法返回的Scheduler与io操作有关,它的实现是后台的一个按需自动增长的线程池,它常用于异步的阻塞的IO操作,不要在此线程中。

Schedulers.newThread()
/**
     * Creates and returns a {@link Scheduler} that creates a new {@link Thread} for each unit of work.
     * <p>
     * Unhandled errors will be delivered to the scheduler Thread's {@link java.lang.Thread.UncaughtExceptionHandler}.
     *
     * @return a {@link NewThreadScheduler} instance
     */
    public static Scheduler newThread() {
        return INSTANCE.newThreadScheduler;
    }

每次创建一个新的线程去执行代码。

Schedulers.immediate()
/**
     * Creates and returns a {@link Scheduler} that executes work immediately on the current thread.
     * 
     * @return an {@link ImmediateScheduler} instance
     */
    public static Scheduler immediate() {
        return ImmediateScheduler.instance();
    }

这个需要注意的一点是immediate()会让代码立即在当前线程运行。

AndroidSchedulers.mainThread()

在先前的代码中,我也也见过AndroidSchedulers.mainThread()。Android开发中只有UI线程也就是主线程能够操作视图的更新,而RxAndroid中当然就提供这种线程的切换。并且这个Scheduler是为Android定制的。
代码非常简单

/** Android-specific Schedulers. */
public final class AndroidSchedulers {
    private AndroidSchedulers() {
        throw new AssertionError("No instances");
    }

    // See https://github.com/ReactiveX/RxAndroid/issues/238
    // https://en.wikipedia.org/wiki/Initialization-on-demand_holder_idiom
    private static class MainThreadSchedulerHolder {
        static final Scheduler MAIN_THREAD_SCHEDULER =
                new HandlerScheduler(new Handler(Looper.getMainLooper()));
    }

    /** A {@link Scheduler} which executes actions on the Android UI thread. */
    public static Scheduler mainThread() {
        Scheduler scheduler =
                RxAndroidPlugins.getInstance().getSchedulersHook().getMainThreadScheduler();
        return scheduler != null ? scheduler : MainThreadSchedulerHolder.MAIN_THREAD_SCHEDULER;
    }
}

内部类保持Looper.getMainLooper()的Handler的引用,自然就能通过这个Handler去操作主线程。

subscribeOn()

指定向subscribe()动作发生的线程。
比如上面例子中的这段代码

public void call(Subscriber<? super String> subscriber) {
    try {
         Thread.sleep(9000);
     } catch (InterruptedException e) {
         e.printStackTrace();
     }
     subscriber.onNext("RxAndroid 找到一个好朋友");
 }
observeOn()

指定观察者得到通知回调时的线程。如

public void call(String s) {
   mTvMsg.setText(s);
  }

正因为.observeOn(AndroidSchedulers.mainThread())所以mTvMsg.setText(s)才能正常显示。


好了,这篇文章到此为此。简单总结一下。

* RxAndroid提供Scheduler对线程进行切换,不然整个事件会在当前现有的线程上发生,如果是在UI线程直接操作耗时工作或者在非UI线程进行UI视图更新,程序将不会按预期进行*

Schedulers提供了几个方法来获取各类Scheduler
Schedulers.immediate()//当前线程立马执行

Schedulers.newThread()//每次创建新线程运行代码

Scheduler.io()//执行IO操作,或者是网络访问耗时但不耗费CPU的操作

Schedulers.computation() //执行图形计算等复杂计算
Observable的API
subscribeOn()//指定subscribe()发生的线程
observeOn() //观察者得到subscrbe的回调通知时所处的线程

未完待续。。。。

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
RxAndroidRxJava 的一个针对 Android 平台的扩展库,它可以帮助我们方便地进行异步编程和线程切换。在 RxAndroid 中,我们可以使用 `observeOn` 操作符指定下游操作符执行的线程,使用 `subscribeOn` 操作符指定上游操作符执行的线程。 下面是一个简单的使用示例,假设我们需要从网络中获取一张图片,然后在主线程中显示该图片: ```java Observable.just(imageUrl) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .map(new Function<String, Bitmap>() { @Override public Bitmap apply(String url) throws Exception { // 从网络中获取图片 return getImageFromUrl(url); } }) .subscribe(new Consumer<Bitmap>() { @Override public void accept(Bitmap bitmap) throws Exception { // 在主线程中显示图片 imageView.setImageBitmap(bitmap); } }); ``` 上面的代码中,`Observable.just(imageUrl)` 创建了一个发射单个数据项的 Observable 对象,该数据项是图片的 URL 地址。`subscribeOn(Schedulers.io())` 指定了上游操作符执行的线程为 IO 线程,即在子线程中发起网络请求。`observeOn(AndroidSchedulers.mainThread())` 指定了下游操作符执行的线程为主线程,即在主线程中进行图片显示操作。`map` 操作符将 URL 地址转换成了 Bitmap 对象,最后通过 `subscribe` 方法订阅 Observable,进行图片显示操作。 需要注意的是,RxAndroid 中提供了多种线程调度器,如 `AndroidSchedulers.mainThread()`、`Schedulers.io()`、`Schedulers.computation()` 等,选择合适的线程调度器非常重要,可以避免因线程阻塞而导致的 ANR 错误和卡顿问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

frank909

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值