Передача данных между длительными потоками (LocalBroadcastManager устарел)

#android #multithreading

#Android #многопоточность

Вопрос:

У меня следующий сценарий: служба переднего плана порождает 2 обработчика (A и B). Время от времени A должен отправлять некоторые данные B, B выполняет определенное действие с этими данными и отправляет обратно A результат операции. Я не знаю, как эффективно передавать данные между этими 2 потоками. Первоначально я отправлял сообщения в поток MainService (через обработчики), который, в свою очередь, отправлял их в соответствующий поток. Но это кажется немного излишним:

  • (поток A) отправить сообщение в обработчик основного потока
  • (основной поток) получает сообщение и отправляет его в обработчик потока B.
  • (поток B) сделайте что-нибудь и отправьте результат обратно в обработчик основного потока
  • (основной поток) получает сообщение и отправляет его в обработчик потока A
  • (поток A) сделайте что-нибудь

Я думал, что мог бы использовать LocalBroadcastManager, но, похоже, сейчас он устарел. У вас есть какие-либо предложения по этому поводу?

РЕДАКТИРОВАТЬ 1

Упрощенная версия программы. Я боюсь, что показанный код станет слишком сложным после добавления дополнительных сигналов между потоками.

MainService.java

 public class MainService extends Service {
    private static final String TAG = "MainService";
    public static final Integer START_A = 0;
    public static final Integer DO_STH_IN_B = 1;
    public static final Integer RESPOND_FROM_B_TO_A = 2;

    private Handler mServiceHandler  = new Handler(Looper.getMainLooper()) {
        // this is a dispatcher for messages between threads
        @Override
        public void handleMessage(@NonNull Message msg) {
            super.handleMessage(msg);

            Message msg_s;

            if (msg.what == DO_STH_IN_B)
                msg_s = Message.obtain(myThreadB.getHandler());
            else if (msg.what == RESPOND_FROM_B_TO_A)
                msg_s = Message.obtain(myThreadA.getHandler());
            else return;

            msg_s.what = msg.what;
            msg_s.sendToTarget();
        }
    };

    private MyThreadA myThreadA = new MyThreadA(mServiceHandler);
    private MyThreadB myThreadB = new MyThreadB(mServiceHandler);

    @Override
    public void onCreate() {
        super.onCreate();
        myThreadA.start();
        myThreadB.start();
        SystemClock.sleep(100);
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Intent notificationIntent = new Intent(this, MainActivity.class);
        PendingIntent pendingIntent =
                PendingIntent.getActivity(this, 0, notificationIntent, 0);

        Notification notification =
                new NotificationCompat.Builder(this, "M_ID")
                        .setContentTitle("Notification Title")
                        .setContentText("Notification Text")
                        .setSmallIcon(R.drawable.ic_android)
                        .setContentIntent(pendingIntent)
                        .build();

        startForeground(1, notification);

        Message msg = Message.obtain(myThreadA.getHandler());
        msg.what = START_A;
        msg.sendToTarget();
        //stopSelf();

        return START_NOT_STICKY;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        myThreadA.quit();
        myThreadB.quit();
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
}

  

MyThreadA.java

 public class MyThreadA extends HandlerThread {
    private static final String TAG = "MyThreadA";
    private Handler mHandler;
    private Handler mMainServiceHandler;

    public MyThreadA(Handler handler) {
        super(TAG, Process.THREAD_PRIORITY_BACKGROUND);
        mMainServiceHandler = handler;
    }

    @SuppressLint("HandlerLeak")
    @Override
    protected void onLooperPrepared() {
        mHandler = new Handler() {
            @Override
            public void handleMessage(@NonNull Message msg) {
                if (msg.what == MainService.START_A) {
                    mHandler.post(myRoutine);
                } else if (msg.what == MainService.RESPOND_FROM_B_TO_A) {
                    mHandler.post(myRoutineRespond);
                }
            }
        };
    }

    public Handler getHandler() { return mHandler; }

    private Runnable myRoutine = new Runnable() {
        @Override
        public void run() {
            Log.d(TAG, "run: [thread A] myRoutine");
            // do something here (may be blocking)
            SystemClock.sleep(1000);

            // send message to Thread B (by passing it through the main service)
            Message msg = Message.obtain(mMainServiceHandler);
            msg.what = MainService.DO_STH_IN_B;
            msg.sendToTarget();

            // repeat the routine
            mHandler.post(myRoutine);
        }
    };

    private Runnable myRoutineRespond = new Runnable() {
        @Override
        public void run() {
            Log.d(TAG, "run: [thread A] respond handler");
            // do something here with the respond from B
            SystemClock.sleep(2000);
        }
    };
}
  

MyThreadB.java

 public class MyThreadB extends HandlerThread {
    private static final String TAG = "MyThreadB";
    private Handler mHandler;
    private Handler mMainServiceHandler;

    public MyThreadB(Handler handler) {
        super(TAG, Process.THREAD_PRIORITY_BACKGROUND);
        mMainServiceHandler = handler;
    }

    @SuppressLint("HandlerLeak")
    @Override
    protected void onLooperPrepared() {
        mHandler = new Handler() {
            @Override
            public void handleMessage(@NonNull Message msg) {
                if (msg.what == MainService.DO_STH_IN_B) {
                    mHandler.post(myRoutine);
                }
            }
        };
    }

    public Handler getHandler() { return mHandler; }

    private Runnable myRoutine = new Runnable() {
        @Override
        public void run() {
            Log.d(TAG, "run: [thread B] do something and respond");
            // do something here (may be blocking)
            SystemClock.sleep(2000);

            // send respond back to Thread A
            Message msg = Message.obtain(mMainServiceHandler);
            msg.what = MainService.RESPOND_FROM_B_TO_A;
            msg.sendToTarget();
        }
    };
}
  

Комментарии:

1. Можете ли вы отредактировать свой пост, чтобы включить в него соответствующие разделы вашего кода? Кроме того, какие данные вы пытаетесь передать и храните ли вы их где-нибудь?

2. @SammyT Я добавил упрощенную версию кода, пожалуйста, взгляните.