11

GreenRobot のEventBusから始めました。

私が苦労していることが 1 つだけあります。それは、onEventXY() メソッドがサブスクライブしたスレッド内でも実際に実行されるように、異なるスレッド間で通信するにはどうすればよいかということです。

イベントを投稿すると、イベントが投稿されたスレッドと同じスレッドからサブスクライバーの onEvent メソッドが呼び出されるようです。それは私が望むものではありません。

イベント オブジェクトを受信したスレッド内の onEvent メソッドによって、実際に受信したイベント オブジェクトが処理されるように、スレッド間通信に EventBus を使用できるようにしたいと考えています。

それは可能ですか?

例:

  • メインスレッド
  • backGroundThread1
  • backGroundThread2

MainThread は EventBus にイベントを投稿し、backGroundThread1 は onEventXY() メソッドでイベントを受け取り、独自のスレッド内でコードを実行します (変数を設定します)。backGroundThread2 は onEventXY メソッドでそれを受け取り、独自のスレッド内でコードを実行します (変数を設定します)。

これが (まだ) 不可能な場合は、実装が難しい BlockingQueue などのスレッド キューを使用する運命にあります。

何か案は?

4

2 に答える 2

3

https://github.com/greenrobot/EventBusの Greenrobot ドキュメントから

BackgroundThread
サブスクライバーはバックグラウンド スレッドで呼び出されます。投稿スレッドがメイン スレッドでない場合、イベント ハンドラー メソッドは投稿スレッドで直接呼び出されます。ポスト スレッドがメイン スレッドの場合、EventBus はすべてのイベントを順番に配信する単一のバックグラウンド スレッドを使用します。このモードを使用するイベント ハンドラーは、バックグラウンド スレッドのブロックを回避するために、迅速に戻ることを試みる必要があります。

Async
イベント ハンドラー メソッドは別のスレッドで呼び出されます。これは、投稿スレッドとメイン スレッドから常に独立しています。このモードを使用すると、ポスト イベントはイベント ハンドラー メソッドを待機しません。イベント ハンドラー メソッドは、ネットワーク アクセスなどの実行に時間がかかる場合に、このモードを使用する必要があります。並行スレッドの数を制限するために、多数の実行時間の長い非同期ハンドラー メソッドを同時にトリガーすることは避けてください。EventBus はスレッド プールを使用して、完了した非同期イベント ハンドラー通知からのスレッドを効率的に再利用します。

コールバックを作成するときは、次のように名前サフィックスを追加する必要がありonEventます。

  • onEventMainThread(YourEvent eventInstance)省略形onEvent(YourEvent eventInstance)
    は常にメイン UI スレッドにディスパッチされます
  • onEventBackgroundThread(YourEvent eventInstance)
    これはあなたの問題に最も適しています
  • onEventAsync(YourEvent eventInstance)
    常に新しいスレッドで、ここから多数のイベントをディスパッチすると危険です。スレッド例外を簡単にヒットできます
于 2014-07-08T13:12:14.840 に答える
3

同じ問題があり、LooperHandler、およびHandlerThreadを使用しました。

それは私の BackgroundHandlerThread クラスです:

import android.annotation.TargetApi;
import android.os.Build;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Message;
import android.os.Process;
import android.util.Log;

import java.lang.reflect.Method;
import java.util.UUID;


public class BackgroundHandlerThread extends Handler {

    private static final String TAG = BackgroundHandlerThread.class.getSimpleName();

    private HandlerThread handlerThread;
    private Object busHandler;

    public BackgroundHandlerThread(HandlerThread handlerThread, Object busHandler) {
        super(handlerThread.getLooper());
        this.handlerThread = handlerThread;
        this.busHandler = busHandler;
    }

    public void onEvent(Object event) {
        Log.d(TAG, "onEvent(Object), thread: " + Thread.currentThread().getId() + ", class: " + event.getClass().getName());
        Message message = obtainMessage();
        message.obj = event;
        sendMessage(message);
    }

    @Override
    public void handleMessage(Message msg) {
        Method[] aClassMethods = busHandler.getClass().getDeclaredMethods();
        for (Method m : aClassMethods) {
            if (m.getName().equals("onHandlerThreadEvent")) {
                if (m.getParameterTypes().length == 1 && m.getParameterTypes()[0].equals(msg.obj.getClass())) {
                    try {
                        m.invoke(busHandler, msg.obj);
                    } catch (Exception e) {
                        Log.wtf(TAG, e);
                    }
                }
            }
        }
    }

    public boolean quit() {
        return handlerThread.quit();
    }

    @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
    public boolean quitSafely() {
        return handlerThread.quitSafely();
    }

    public static class Builder {
        private HandlerThread handlerThread;
        private Object busHandler;

        public Builder(Object busHandler) {
            this.busHandler = busHandler;
        }

        public Builder setHandlerThread(HandlerThread handlerThread) {
            this.handlerThread = handlerThread;
            return this;
        }

        public BackgroundHandlerThread build() {
            if (handlerThread == null) {
                handlerThread = new HandlerThread("BackgroundHandlerThread: " + UUID.randomUUID().toString(), Process.THREAD_PRIORITY_BACKGROUND);
            }

            if (!handlerThread.isAlive()) {
                handlerThread.start();
            }

            return new BackgroundHandlerThread(handlerThread, busHandler);
        }
    }
}

サービスで使用しましたが、BackgroundHandlerThread オブジェクトは任意のオブジェクトにバインドできます。

import android.app.Service;
import android.bluetooth.BluetoothDevice;
import android.content.Context;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.util.Log;

import de.greenrobot.event.EventBus;

public class DeviceService extends Service {

    private static final String TAG = DeviceService.class.getSimpleName();

    private BluetoothDevice bluetoothDevice;
    private BackgroundHandlerThread handlerThread;
    private boolean connected = false;

    //region Lifecycle
    @Override
    public void onCreate() {
        super.onCreate();
        Log.d(TAG, "onCreate, thread: " + Thread.currentThread().getId());
        handlerThread = new BackgroundHandlerThread.Builder(this).build();
        EventBus.getDefault().register(handlerThread);
    }

    @Override
    public void onDestroy() {
        EventBus.getDefault().unregister(handlerThread);
        handlerThread.quit();
        super.onDestroy();
    }
    //endregion

    public void onHandlerThreadEvent(ConnectToDeviceEvent event) {
        Log.d(TAG, "onHandlerThreadEvent, thread: " + Thread.currentThread().getId());
        connected = true;
        bluetoothDevice = event.device;
        EventBus.getDefault().post(new ConnectionStateChangedEvent(bluetoothDevice, connected));
    }

    //region Static manipulation
    public static void startService(Context context) {
        Intent intent = new Intent(context, DeviceBinder.class);
        context.startService(intent);
    }
    //endregion
}

そして活動クラス:

import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.util.Log;

import de.greenrobot.event.EventBus;

public class MainActivity extends Activity {

    private static final String TAG = MainActivity.class.getSimpleName();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        findViewById(R.id.startButton).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Log.d(TAG, "onStartClick, thread: " + Thread.currentThread().getId());
                EventBus.getDefault().post(new ConnectToDeviceEvent(application.getCurrentStateProvider().getDevice()));
            }
        });
        DeviceService.startService(this);
    }

    @Override
    protected void onStart() {
        super.onStart();
        EventBus.getDefault().register(this);
    }

    @Override
    protected void onStop() {
        EventBus.getDefault().unregister(this);
        super.onStop();
    }

    public void onEventMainThread(ConnectionStateChangedEvent event) {
        Log.d(TAG, "onEventMainThread(ConnectionStateChangedEvent), thread: " + Thread.currentThread().getId());
    }

}

ログ出力:

D/MainActivity: onStartClick, thread: 1
D/BackgroundHandlerThread: onEvent(Object), thread: 1, class: ConnectToDeviceEvent
D/DeviceService: onHandlerThreadEvent, thread: 4399
D/BackgroundHandlerThread: onEvent(Object), thread: 4399, class: ConnectionStateChangedEvent
D/MainActivity: onEventMainThread(ConnectionStateChangedEvent), thread: 1

類似:スレッド セーフなイベントバスのベスト プラクティス

于 2015-10-08T19:55:25.087 に答える