RX系列五 | Schedulers线程控制

Posted 刘某人程序员

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了RX系列五 | Schedulers线程控制相关的知识,希望对你有一定的参考价值。

RX系列五 | Schedulers线程控制


在我们上一篇文章中的,我们的小例子里有这么一段代码

//网络访问
.observeOn(Schedulers.io())

事实上,我们在使用网络操作的时候,便可以控制其运行在哪个线程中,而Schedulers类,有四个方法,分别是

  • Schedulers.immediate();
  • Schedulers.newthread();
  • Schedulers.io();
  • Schedulers.computation();

以及Rxandroid中的AndroidSchedulers有一个

  • AndroidSchedulers.mainThread();

这些都是操作线程的方法,我们都知道RxJava在异步方面很优秀,那我们应该怎么去体现他尼,先来看下这几个函数的具体含义吧

Schedulers.immediate()

作用于当前线程运行,相当于你在哪个线程执行代码就在哪个线程运行

Schedulers.newthread();

运行在新线程中,相当于new Thread(),每次执行都会在新线程中

Schedulers.io();

一看便知,I/O操作,比如文件操作,网络操作等,他和newThread有点类似,不过I/O里面有一个死循环的线程池来达到最大限度的处理逻辑,虽然效率高,但是如果只是一般的计算操作,不建议放在这里,避免重复创建无用线程

Schedulers.computation()

一些需要CPU计算的操作,比如图形,视频等

AndroidSchedulers.mainThread();

指定运行在Android主线程中

我们现在就来模拟这个操作,比如我们去加载一张图片,那么我们使用okhttp的话,代码应该怎么写

  @Override
    public void onClick(final View v) {
        switch (v.getId()) {
            case R.id.load_img:
                Observable.create(new ObservableOnSubscribe<Bitmap>() {
                    //主线程执行
                    @Override
                    public void subscribe(final ObservableEmitter<Bitmap> e1) throws Exception {
                        //进行网络操作 解析图片
                        OkHttpClient client = new OkHttpClient();
                        Request request = new Request.Builder().url(IMG_URL).build();
                        //异步方法
                        client.newCall(request).enqueue(new Callback() {
                            @Override
                            public void onFailure(Call call, IOException e) {
                                e1.onError(e);
                            }

                            @Override
                            public void onResponse(Call call, Response response) throws IOException {
                                if (response.isSuccessful()) {
                                    byte[] bytes = response.body().bytes();
                                    Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
                                    e1.onNext(bitmap);
                                    e1.onComplete();
                                }
                            }
                        });
                    }
                }).subscribe(new Observer<Bitmap>() {
                    @Override
                    public void onSubscribe(Disposable d) {
                        Log.e("MainActivity", "onSubscribe");
                    }

                    @Override
                    public void onNext(Bitmap bitmap) {
                        Log.e("MainActivity", "onNext");

                    }

                    @Override
                    public void onError(Throwable e) {
                        Log.e("MainActivity", "onError" + e.toString());
                    }

                    @Override
                    public void onComplete() {
                        Log.e("MainActivity", "onComplete");
                    }
                });
                break;
        }
    }

嗯,可以的,然后我们运行,会出现什么日志尼

com.liuguilin.schedulerssample E/MainActivity: onSubscribe
com.liuguilin.schedulerssample E/MainActivity: android.os.NetworkOnMainThreadException

他提示我们不能在主线程进行网络操作,那好,可以下的结论是subscribe在主线程,那现在我们的Schedulers就派上用场了,我们只需要

.subscribeOn(Schedulers.io())

让其在I/O操作即可,而这些含义,上面也都有提及,那我们现在运行,可以看到如下的打印

com.liuguilin.schedulerssample E/MainActivity: onSubscribe
com.liuguilin.schedulerssample E/MainActivity: onNext
com.liuguilin.schedulerssample E/MainActivity: onComplete

好的,走了onnext说明我们加载是成功的,因为我是加载图片,所有我现在来加载这张图片,这个很简单,我们只需要设置就好了

@Override
public void onNext(Bitmap bitmap) {
    Log.e("MainActivity", "onNext");
    iv_img.setImageBitmap(bitmap);

}

但是当你运行 你就会发现,又出现错误了

CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.

这个错误你一定不陌生,这就是在子线程更新UI的错误,其实这里也很好理解,就是我们在网络操作的时候是在子线程中,是吧,所有我们设置图片才会有这样的错误,其实解决的办法,就是将我们的消费者切换成我们的主UI线程就好了,添加一行

.observeOn(AndroidSchedulers.mainThread())

好的,现在我们运行一下看下效果

这里写图片描述

OK,全部的代码就这么点,就一个小知识点,但是一定要清楚他的工作流程

    @Override
    public void onClick(final View v) {
        switch (v.getId()) {
            case R.id.load_img:
                Observable.create(new ObservableOnSubscribe<Bitmap>() {
                    //主线程执行
                    @Override
                    public void subscribe(final ObservableEmitter<Bitmap> e1) throws Exception {
                        //进行网络操作 解析图片
                        OkHttpClient client = new OkHttpClient();
                        Request request = new Request.Builder().url(IMG_URL).build();
                        //异步方法
                        client.newCall(request).enqueue(new Callback() {
                            @Override
                            public void onFailure(Call call, IOException e) {
                                e1.onError(e);
                            }

                            @Override
                            public void onResponse(Call call, Response response) throws IOException {
                                if (response.isSuccessful()) {
                                    byte[] bytes = response.body().bytes();
                                    Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
                                    e1.onNext(bitmap);
                                    e1.onComplete();
                                }
                            }
                        });
                    }
                }).subscribeOn(Schedulers.io())
                        .observeOn(AndroidSchedulers.mainThread())
                        .subscribe(new Observer<Bitmap>() {
                            @Override
                            public void onSubscribe(Disposable d) {
                                Log.e("MainActivity", "onSubscribe");
                            }

                            @Override
                            public void onNext(Bitmap bitmap) {
                                Log.e("MainActivity", "onNext");
                                iv_img.setImageBitmap(bitmap);

                            }

                            @Override
                            public void onError(Throwable e) {
                                Log.e("MainActivity", "onError" + e.toString());
                            }

                            @Override
                            public void onComplete() {
                                Log.e("MainActivity", "onComplete");
                            }
                        });
                break;
        }
    }

在线程操作的时候,自己只要清楚使用哪一个Schedulers就好了,这个例子比较简单,但是如果你的逻辑很复杂的话,而且需要来回的线程切换的时候,这个rxjava的优势就出来了,我们以后慢慢的深入吧!

Sample下载:http://download.csdn.net/detail/qq_26787115/9792294

以上是关于RX系列五 | Schedulers线程控制的主要内容,如果未能解决你的问题,请参考以下文章

Rxjava 源码解析 - Schedulers默认线程池

Rxjava 源码解析 - Schedulers默认线程池

聊一聊线程池和Kotlin协程

线程基础知识系列(五)认识volatile

Rx Java Android 中的困惑

java并发系列-----线程之间的协作(waitnotifyjoinCountDownLatchCyclicBarrier)