Ответ 1
Я не уверен, будет ли библиотека для этого, поскольку Android уже предоставляет высокоуровневые строительные блоки для того, чего вы пытаетесь достичь.
Обработчик
Если вы правильно поняли, вы хотите публиковать задания из любого потока, который должен быть поставлен в очередь и выполняться один за другим в отдельном потоке. Это очень то, на что рассчитан Android Handler
.
Основные черты обработчика, Looper и MessageQueue
- Обработчик привязан к одному
Looper
. - Каждый
Looper
имеет связанныйMessageQueue
- Обработчик использует
Looper
снизу для размещения и удаления сообщений в потоковом режиме вLooper
MessageQueue
. - Объекты обработчика по сути являются потокобезопасными и, следовательно, могут безопасно передаваться другим потокам.
- У вас может быть несколько объектов
Handler
, привязанных к одному и тому жеLooper
. Это полезно, если вы хотите обрабатывать различные типы сообщений с помощью разных обработчиков. В этом случае вам гарантируется, что только один из обработчиков обработает Message/Runnable для данногоLooper
.Looper
позаботится о том, чтобы отправить сообщение вправоHandler
. - Если вы уже знакомы с парадигмой очереди сообщений для связи между двумя потоками (или аналогичным шаблоном буферизованного канала
golang
),Handler
- это просто класс высокого уровня, который позволяет легко использовать этот шаблон.
Пример использования Handler для отправки/получения сообщений, post Runnables
// BEGIN One-time Initialization
// Create a Handler thread
// This provides the looper for the Message Queue and
// will be processing all your messages (i.e. tasks).
handlerThread = new HandlerThread("SomeThreadName");
// Start the Handler Thread
// The thread will block (using the looper) until it
// receives a new message
handlerThread.start();
// Create a Message Handler which you can use to
// post and process messages
// The same Handler can also be used to post a Runnable which will get
// executed on handlerThread
handler = new CustomHandler(mHandlerThread.getLooper());
// END One-time Initialization
// Different ways to post a message to the Handler Thread
// These calls are thread-safe, can be called safely and
// concurrently from multiple threads without race conditions
handler.sendEmptyMessage(MESSAGE_ID_1);
handler.sendEmptyMessage(MESSAGE_ID_2);
handler.sendMessage(handler.obtainMessage(MESSAGE_ID_3, obj1));
handler.sendMessage(handler.obtainMessage(MESSAGE_ID_4, value, obj1));
handler.sendMessage(handler.obtainMessage(MESSAGE_ID_5, value1, valu2, obj1));
// Post a runnable on the Handler Thread
// This is thread-safe as well
// In fact all methods on the Handler class are thread-safe
handler.post(new Runnable() {
@Override
public void run() {
// Code to run on the Handler thread
}
});
// A skeleton implementation for CustomHandler
// NOTE: You can use the Handler class as-is without sub-classing it, if you
// intend to post just Runnables and NOT any messages
public class CustomHandler extends Handler {
public CustomHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message message) {
if (message != null) {
// Process the message
// The result can be sent back to the caller using a callback
// or alternatively, the caller could have passed a Handler
// argument, which the Handler Thread can post a message to
switch (message.what) {
case MESSAGE_ID_1:
// Some logic here
break;
case MESSAGE_ID_2:
// Some logic here
break;
case MESSAGE_ID_3:
// Some logic here
break;
case MESSAGE_ID_4:
// Some logic here
break;
case MESSAGE_ID_5:
// Some logic here
break;
// Add more message types here as required
}
}
}
}
// After you're done processing all messages and you
// want to exit the Handler Thread
// This will ensure that the queue does not accept any
// new messages, and all enqueued messages do get processed
handlerThread.quitSafely();
Отклонения от приведенного выше примера
- Хотя я использовал
HandlerThread
в приведенном выше примере, его не обязательно использовать. Вы можете даже напрямую использовать вызовыLooper
, т.е.Looper.prepare()
иLooper.loop()
, чтобы запустить собственный цикл сообщений в потоке. - Как уже упоминалось в комментариях, вам не нужно подклассифицировать запас
Handler
, если вы не собираетесь обрабатывать какие-либо сообщения. - Вы можете легко общаться между несколькими потоками, используя
Handler
для каждого потока, который должен получать сообщение. - В
Handler
есть методы для планирования доставки сообщений и выполнения Runnable в будущем.
Каркас Android внутри себя использует Handler
для управления событиями жизненного цикла компонентов (onPause
, onResume
и т.д.).
AsyncTask
AsyncTask - еще одна альтернатива планированию задач в другом потоке., Я не буду вдаваться в подробности его реализации, поскольку документация разработчика Android уже подробно описывает его.
Я обычно использую AsyncTasks для задач, которые, как я знаю, я буду использовать фоновый поток в течение длительного времени (легко >= 100 мс, по крайней мере). Некоторые примеры, которые относятся к этой категории, я могу думать о Binder IPC, RPC-вызовах, сетевых вызовах, загрузке фонограмм и т.д.
С другой стороны, Handler
более адаптирован для ситуаций, сфокусированных на обработке большего количества сообщений как можно быстрее. Другими словами, избегайте выполнения какой-либо операции блокировки в handleMessage()
. Вы можете легко писать код без блокировки, используя Handler
, он управляет всей блокировкой для вас при вводе и удалении сообщений.
Фактически AsyncTask
можно использовать в сочетании с Handler
, разбивая работу на быструю часть (заботясь о Handler
) и медленной части (позаботится AsyncTask
).
PS: Хотя касательно вопроса, если вас интересует парадигма очереди сообщений; посмотрите LMAX Disruptor
, которая является высокопроизводительной межпоточной библиотекой очереди сообщений. Их проектный документ очень хорошо объясняет, в каких частях очереди сообщений требуется блокировка/атомный доступ.