RxJava 2修練の道(二)

8787 ワード

RaJava 2修練の道——易容術
前編でRxJavaの原理を説明した後、本編ではRxJavaがタスクを実行するスレッドのスケジューリングについてさらに深く理解します.
目的
Androidを習ったばかりのシロにとって、覚えておきたいのは、サブスレッドが新しいUIに接続できないことです.新しいUIとの操作はすべてメインスレッド(つまりUIスレッド)に置かなければなりません.何を聞きますか.インタフェースカートンやANRになるから、ANRとは何か聞きたいなら?では、まず資料を調べて充電してから、この文章を見てみましょう.新しいUIとの操作がサブスレッドでプログラムが潰れてしまいます.次は私が書いた例です.Handlerを利用して新しいUIと付き合います.
 handler = new Handler(){
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                Log.d(TAG, "handleMessage: "+Thread.currentThread().getName());
                if(msg.what == 0x01){
                    Bitmap bmp = (Bitmap) msg.obj;
                    loadPic(bmp);
                }
            }
        };

  /**
     *   UI
     *
     * @param bmp
     */
    private void loadPic(Bitmap bmp) {
        img.setImageBitmap(bmp);
    }
    @Override
    protected void onResume() {
        super.onResume();
        new Thread() {//        
            @Override
            public void run() {
                Bitmap bmp = loadImage();
                Message msg = handler.obtainMessage();
                msg.obj = bmp;
                msg.what = 0x01;
                handler.sendMessage(msg);
            }
        }.start();
    }

    /**
     *     
     *
     * @return
     */
    private Bitmap loadImage() {
        Bitmap bmp = null;
        try {
            URL url = new URL(mUrl);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod("GET");
            conn.setConnectTimeout(8 * 1000);
            conn.setReadTimeout(8 * 1000);
            InputStream is = conn.getInputStream();
            bmp = BitmapFactory.decodeStream(is);
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return bmp;
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        handler.removeCallbacksAndMessages(null);//     handler     
    }


簡単なネットワークロード画像であり、UIインタフェースに表示され、OnResumeでスレッドを開いてロード画像を実行する時間のかかる操作であり、画像ロードが完了した後、メッセージに画像を埋め込んでHandlerMessageに伝え、UIを実行して新しいものを実行し、HandlerはAndroidの重要な知識点であり、よく分からない仲間は資料を調べて補足しましょう.
インプリメンテーション
まず、RxJavaでのイベントの送信と受信を見てみましょう.
     Observable.create(new ObservableOnSubscribe() {
            @Override
            public void subscribe(ObservableEmitter e) throws Exception {
                Log.d(TAG, "accept: "+Thread.currentThread().getName());
                 e.onNext("hello world");
                 e.onComplete();
            }
          }).subscribe(new Consumer() {
            @Override
            public void accept(String  str) throws Exception {
                Log.d(TAG, "accept: "+Thread.currentThread().getName());
            }
        });
        }

印刷結果:
09-02 10:34:10.065 22364-22364/ruanrong.com.rxjava2demo D/tag: subscribe: main
09-02 10:34:10.067 22364-22364/ruanrong.com.rxjava2demo D/tag: accept: main

明らかに、送信イベントと受信イベントのデフォルトはMain、すなわちUIスレッドです.では、送信イベントをサブスレッドに、新しいイベントをUIスレッドにするにはどうすればいいのでしょうか.ここでは,RxJavaのスレッドスケジューラSchedulerという新しい概念を導入し,Schedulers内部には6つのスケジューリングタイプが含まれている.
  • Schedulers.イベントループやコールバック処理などのタスクの計算に使用され、IO操作では使用されません(IO操作はSchedulers.io()を使用してください).デフォルトのスレッド数は、プロセッサの数に等しい
  • Schedulers.from(executor)は、指定されたExecutorをスケジューラ
  • として使用する.
  • Schedulers.immediate(
  • Schedulers.io( )は、非同期でIO操作をブロックするなど、IO密集型タスクに使用され、このスケジューラのスレッドプールは必要に応じて増加します.通常の計算タスクでは、Schedulersを使用します.computation();Schedulers.io( )デフォルトはCachedThreadSchedulerであり、スレッドキャッシュされた新しいスレッドスケジューラ
  • に似ています.
  • Schedulers.新Thread( )は、タスクごとに新しいスレッド
  • を作成する.
  • Schedulers.trampoline( )他のキューのタスクが完了すると、現在のスレッドキューで実行が開始されます.また、
  • という特殊なスケジューリングタイプもあります.
    AndroidSchedulers.mainThread()このスケジューリングタイプはUIスレッドで発生する唯一の決定である
    上はスレッドスケジューラの6つのタイプで、いずれもSchedulesクラスの静的定数です.次は変身の時だ.
       Observable.create(new ObservableOnSubscribe() {
                @Override
                public void subscribe(ObservableEmitter e) throws Exception {
                    Log.d(TAG, "subscribe: "+Thread.currentThread().getName());
                     e.onNext("hello world");
                     e.onComplete();
                }
              }).subscribeOn(Schedulers.newThread()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Consumer() {
                @Override
                public void accept(String  str) throws Exception {
                    Log.d(TAG, "accept: "+Thread.currentThread().getName());
                }
            });
            }
    

    印刷結果:
    09-02 10:59:12.717 12326-12357/ruanrong.com.rxjava2demo D/tag: subscribe: RxNewThreadScheduler-1
    09-02 10:59:12.729 12326-12326/ruanrong.com.rxjava2demo D/tag: accept: main                                                             
    

    案の定、イベントをサブスレッドに送信し、新しいメインスレッドでの操作を完了し、次に画像のダウンロード更新をRxJavaに置いて実行します.
     Observable.create(new ObservableOnSubscribe() {
                @Override
                public void subscribe(ObservableEmitter e) throws Exception {
                    Log.d(TAG, "accept: "+Thread.currentThread().getName());
                    Bitmap bmp = loadImage();
                     e.onNext(bmp);
                     e.onComplete();
                }
            }).subscribeOn(Schedulers.newThread()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Consumer() {
                @Override
                public void accept(Bitmap bitmap) throws Exception {
                    Log.d(TAG, "accept: "+Thread.currentThread().getName());
                    img.setImageBitmap(bitmap);
                }
            });
    

    では、画像は正常に表示されます.それなら、onSubscribeとonObserverでスレッドを何度も指定したら?たとえば、次のようになります.
          Observable.create(new ObservableOnSubscribe() {
                @Override
                public void subscribe(ObservableEmitter e) throws Exception {
                    Log.d(TAG, "accept: "+Thread.currentThread().getName());
                    e.onNext("hello world");
                    e.onComplete();
                }
            }).subscribeOn(Schedulers.newThread())
                    .subscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread())
                    .observeOn(Schedulers.newThread())
                    .subscribe(new Consumer() {
                @Override
                public void accept(String  str) throws Exception {
                    Log.d(TAG, "accept: "+Thread.currentThread().getName());
                }
            });
        }
    

    印刷結果:
    09-02 11:09:51.315 21666-21686/? D/tag: subscribe: RxNewThreadScheduler-1
    09-02 11:09:51.329 21666-21688/? D/tag: accept: RxNewThreadScheduler-2
    

    サブスクリプションイベント選択が最も近いスレッドスケジューリング方式を設定し、観察者が最後のスレッドスケジューリング方式を選択することを説明できます.サブスレッドサブスレッドオブザーバでサブスレッドオブザーバを完了した以上、このような処理に時間がかかるタスクの過程でActivityは破棄されますか?ここでは前編のDisposiableオブジェクトを用い,Activity破棄時にイベント送信を終了する.
     Observable.create(new ObservableOnSubscribe() {
                @Override
                public void subscribe(ObservableEmitter e) throws Exception {
                    Log.d(TAG, "accept: "+Thread.currentThread().getName());
                    Bitmap bmp = loadImage();
                     e.onNext(bmp);
                     e.onComplete();
                }
            }).subscribeOn(Schedulers.newThread())
                    .observeOn(AndroidSchedulers.mainThread())
                    .subscribe(new Observer() {
                        @Override
                        public void onSubscribe(Disposable d) {
                            mDisposable = d;
                        }
    
                        @Override
                        public void onNext(Bitmap value) {
                            img.setImageBitmap(value);
                        }
                        @Override
                        public void onError(Throwable e) {
                        }
                        @Override
                        public void onComplete() {
                        }
                    });
    
     @Override
        protected void onDestroy() {
            super.onDestroy();
            handler.removeCallbacksAndMessages(null);
            if(!mDisposable.isDisposed()){
                mDisposable.dispose();
            }
        }
    

    では、Disposableが複数あるとしたら?ここにはDisposable専用の容器類CompositeDisposableがあり、中には`OpenHashSet resourcesがメンテナンスされています.集合ですので、登録時にDisposableをCompositeDisposableに追加し、Activity破棄時にその容器Clearを落とすだけです.さて、RxJavaのイベントスケジューリングは、イベント実行のスレッドを変更するために使用されます.