EventBusのスレッド配布


EventBusはスレッド配布をサポートし、前のブログEventBusの概要と初歩的な使用では、EventBusの使用が主にイベント送信者、イベント購読者に関連していることが分かった.送信とサブスクリプションの2つの動作については、異なるスレッドでEventBusのスレッド配布が可能です.スレッドの設定については、サブスクリプションメソッドで@Subscribe注記を使用して、コードに示すようにスレッドの調整を行うことができます.
@Subscribe(threadMode = ThreadMode.MAIN)
    public void showContent(MessageEvent messageEvent){
        showContentTv.setText(messageEvent.getMessage());
    }

上のコードでは、サブスクリプションのこの方法はメインスレッドで実行されます.ThreadModeには5つの値があります.それぞれ:-ThreadModeです.POSTING - ThreadMode.MAIN - ThreadMode.MAIN_ORDERED - ThreadMode.BACKGROUND - ThreadMode.ASYNC

ThreadMode.POSTING


これはデフォルトのポリシーで、サブスクリプション処理されたスレッドとイベントが同じスレッドに生成されます.このモデルは,スレッド切替を必要としないため,オーバーヘッドが最小である.したがって,このモデルでは,UIマスタースレッドを必要としない単純なタスクを実行することを提案する.購読方法を次のように変更した場合、上記のブログの例を説明します.
@Subscribe()
    public void showContent(MessageEvent messageEvent){
        showContentTv.setText(messageEvent.getMessage());
    }

プログラムを再実行すると、Activity AはActivity Bから渡された内容を表示せず、logcatに次の異常情報が表示されます.
Could not dispatch event: class com.example.wangli.eventbusdemo.MessageEvent to subscribing class class com.example.wangli.eventbusdemo.MainActivity
    android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views

この異常は、UI以外のスレッドでUIを操作できないことを示していることがわかります.上記の注記は次のようになります.
@Subscribe(threadMode=ThreadMode.POSTING)

ThreadMode.MAIN


Androidプラットフォームでは、購読メソッドがUIスレッドで呼び出され、イベントがプライマリスレッドで発生した場合、処理もプライマリスレッドで直接呼び出され、イベントの発生をブロックするため、メソッドの処理に時間がかかる.そうでないと、プライマリ・スレッド処理のキューに入ります.Android以外のプラットフォームであれば、POSTINGと同じです.たとえば、Activity Aの購読方法を以下のように変更します.
@Subscribe(threadMode = ThreadMode.MAIN)
    public void showContent(MessageEvent messageEvent){
        showContentTv.setText(messageEvent.getMessage());
        Log.i("TAG","Activity A");
    }

イベントはメインスレッドで生成されます


イベントがメインスレッドに生成されると、イベント処理はイベント生成をブロックし、Activity Bのコードは以下の通りである.
 protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);

        MessageEvent messageEvent = new MessageEvent();
        messageEvent.setMessage("Hello World From Network");
        EventBus.getDefault().post(messageEvent);
        Log.i("TAG", "Activity B");
        finish();

    }

この場合の実行ログは次のとおりです.
Activity A  
Activity B

発生イベントがブロックされているため、Activity Aのログを印刷してからActivity Bのログを印刷します.

イベントは非プライマリスレッドで生成されます


イベントがプライマリ・スレッドに存在しない場合、キューに入ります.相対的に非同期動作であり、Activity Bのコードを次のように変更します.
 protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);
        new Thread(new Runnable() {
            @Override
            public void run() {

                // 
                try {
                    TimeUnit.SECONDS.sleep(2);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                MessageEvent messageEvent=new MessageEvent();
                messageEvent.setMessage("Hello World From Network");
                EventBus.getDefault().post(messageEvent);
                Log.i("TAG","Activity B");
                finish();

            }
        }).start();

    }

実行結果は次のとおりです.
Activity B
Activity A

ThreadMode.MAIN_ORDERED


Androidプラットフォームでは、UIスレッドで処理が呼び出されます.MAINとは異なり、常にプライマリスレッドのキューに配布され、postスレッドはブロックされません.Activity Aイベント処理を次のように変更します.
@Subscribe(threadMode = ThreadMode.MAIN_ORDERED)
    public void showContent(MessageEvent messageEvent){
        showContentTv.setText(messageEvent.getMessage());
        Log.i("TAG","Activity A");
    }

Activity B postスレッドもプライマリスレッドに変更され、次のように実行されます.
Activity B
Activity A

非同期なのでMAINとは状況が違います.

ThreadMode.BACKGROUND


Androidプラットフォームでは、イベント処理がbackgroundスレッドで呼び出されます.postがプライマリスレッドでない場合、イベント処理はpostスレッドで直接呼び出されます.postがプライマリ・スレッドである場合、EventBusが単一のbackgroundスレッドを使用すると、すべてのプライマリ・スレッドpostのイベントがキュー順に入るため、backgroundスレッドをブロックすることなく、イベント処理ができるだけ迅速に戻る必要があります.androidプラットフォームでない場合、backgroundスレッドは常に使用されます.Activity Aのコードを次のように変更します.
@Subscribe(threadMode = ThreadMode.BACKGROUND)
    public void showContent(MessageEvent messageEvent){
//        showContentTv.setText(messageEvent.getMessage());
        Log.i("TAG",Thread.currentThread().getName()+"  "+messageEvent.getMessage());
    }

Activity Bのコードを次のように変更します.
 protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);

        new Thread(new Runnable() {
            @Override
            public void run() {

                // 
                try {
                    TimeUnit.SECONDS.sleep(2);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                MessageEvent messageEvent=new MessageEvent();
                messageEvent.setMessage("Hello World From Network");
                EventBus.getDefault().post(messageEvent);
                Log.i("TAG",Thread.currentThread().getName());
                finish();

            }
        }).start();

        MessageEvent messageEvent = new MessageEvent();
        messageEvent.setMessage("Hello World From Network");
        EventBus.getDefault().post(messageEvent);
        Log.i("TAG-Main", Thread.currentThread().getName());


        messageEvent.setMessage("Hello");
        EventBus.getDefault().post(messageEvent);
        Log.i("TAG-Main", Thread.currentThread().getName());


        finish();


    }

最終的な実行結果は次のとおりです.
TAG-Main: main
TAG-Main: main
TAG: pool-1-thread-1  Hello
TAG: pool-1-thread-1  Hello
TAG: Thread-210  Hello World From Network
TAG: Thread-210

いくつかの問題が発見され、postはプライマリスレッドであり、backgroundスレッドは常に同じである.postはプライマリスレッドではなく、backgroundはpostと同じであり、イベント処理はpostスレッドをブロックします.

ThreadMode.ASYNC


イベント処理は常に個別のスレッドにあります.常にpostスレッドとmainスレッドとは独立しています.ネットワーク操作や大量の演算などの操作に時間がかかる場合は、このモードを使用し、EventBusバックグラウンドでスレッドプールを使用してスレッドを管理する必要があります.上記の例に続いて、イベント処理をASYNCに変更します.
@Subscribe(threadMode = ThreadMode.ASYNC)
    public void showContent(MessageEvent messageEvent){
//        showContentTv.setText(messageEvent.getMessage());
        Log.i("TAG",Thread.currentThread().getName()+"  "+messageEvent.getMessage());
    }

Activity Bのpostロジックは変わらず、結果は以下の通りです.
TAG-Main: main
TAG: pool-1-thread-1  Hello
TAG-Main: main
TAG: pool-1-thread-2  Hello
TAG: Thread-215
TAG: pool-1-thread-2  Hello World From Network

イベント処理は常にオンライン・スレッド・プールのスレッドにあることがわかります.

まとめ


以上の解析により,各ThreadModeの使用シーンやpostスレッドとは異なり,どのような表現があるかが分かる.
スレッドのパブリッシュ
Androidマスタースレッド
非Androidマスタースレッド、スレッドa
POSTING
Androidマスタースレッド
非Androidスレッド、スレッドa
MAIN
Androidメインスレッド、メインスレッドのリリースをブロック
メインスレッドへのキュー
MAIN_ORDERED
メインスレッドキュー
Androidプラットフォームはメインスレッドキューに入り、JavaプラットフォームはPOSTINGと同じです
BACKGROUND
backgroundスレッド
非Androidマスタースレッド、スレッドa
ASYNC
個別スレッドc
個別スレッドc
表では、ヘッダーはパブリッシュされたスレッドを表し、サブスクリプションメソッドは異なるThreadModeにあり、サブスクリプションメソッドはどのスレッドで実行されますか.表では、ヘッダーはパブリッシュされたスレッドを表し、サブスクリプションメソッドは異なるThreadModeにあり、サブスクリプションメソッドはどのスレッドで実行されますか.