#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 Я добавил упрощенную версию кода, пожалуйста, взгляните.