Android上是否有任务队列这样的东西?我知道它可以手动编写,但是否有现成的库可供使用?
Android上是否有任务队列这样的东西?我知道它可以手动编写,但是否有现成的库可供使用?
我不确定是否有这方面的库,因为Android已经提供了高级构建块来实现您要实现的目标。
如果我理解正确,您想从任何线程中发布任务以便在专用线程上按顺序排队并执行。这正是 Android Handler
的作用。
Looper
。Looper
关联一个 MessageQueue
。Looper
,以线程安全的方式将消息排队到 Looper
的 MessageQueue
中进行出队和处理。Looper
上。这对于使用不同的 Handler 处理不同类型的消息很有用。在这种情况下,你可以确保只有一个 Handler 会处理给定 Looper
上的消息/Runnable。Looper 负责将 Message 分发到正确的 Handler。Handler
就是一个让你轻松使用此模式的高级类。// 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是另一种在不同线程上调度任务的选择。我不会详细介绍它的实现方式,因为Android开发者文档已经对其进行了详细描述。
我通常使用AsyncTasks来处理长时间运行的后台线程任务(至少轻松地>= 100毫秒)。我能想到的一些属于这个类别的例子是Binder IPC、RPC调用、网络调用、后台下载等。
另一方面,Handler
更适合于专注于尽可能快地处理更多数量的消息的情况。换句话说,避免在handleMessage()
中执行任何阻塞操作。您可以使用Handler
轻松编写无锁代码,它在排队和出队消息时管理所有锁定。
实际上,AsyncTask
可以与Handler
结合使用,通过将工作分成快速部分(由Handler
处理)和慢速部分(由AsyncTask
处理)。
附:虽然与问题无关,但如果您对消息队列范例感兴趣,请查看LMAX Disruptor
,这是一个高性能的跨线程消息队列库。他们的设计文档很好地解释了消息队列的哪些部分需要锁定/原子访问。
我也曾经寻找类似于GCD的东西来用在Android上。虽然Handlers和AsyncTasks也很棒,但是我认为GCD的精髓在于可以将工作负载派发到后台线程进行处理,当执行完成后,轻松地在UI线程上执行UI更新。
由于我没有找到任何现成的解决方案,所以我和我的学校同伴决定自己创建一个。你可以在以下链接找到它:
基本上,你只需要声明一个继承自ICDispatchApplication而不是Application的Application类,当你想要调度某些任务时,只需调用以下命令:
App.executeOn(int queue, ICBlock block);
例如:
App.executeOn(ICDispatch.NORMAL, new ICBlock(){
public void run(){
//do stuff...
App.executeOn(ICDispatch.MAIN, new ICBlock(){
public void run(){
//post result to UI thread.
}
}
}
});
App.executeOn(ICDispatch.NORMAL, ()->{
//do stuff...
//do some more...
//then even more
App.executeOn(ICDispatch.MAIN,() -> {
//Post result on UI thread.
}
});
目前ICDispatch支持LOW、NORMAL、HIGH、MAIN和CONCURRENT队列。随着实现的功能,将添加更多特性。
public static volatile DispatchQueue globalQueue = new DispatchQueue("globalQueue");
这个类是:
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import java.util.concurrent.CountDownLatch;
public class DispatchQueue extends Thread {
private volatile Handler handler = null;
private CountDownLatch syncLatch = new CountDownLatch(1);
public DispatchQueue(final String threadName) {
setName(threadName);
start();
}
private void sendMessage(Message msg, int delay) {
try {
syncLatch.await();
if (delay <= 0) {
handler.sendMessage(msg);
} else {
handler.sendMessageDelayed(msg, delay);
}
} catch (Exception e) {
FileLog.e("tmessages", e);
}
}
public void cancelRunnable(Runnable runnable) {
try {
syncLatch.await();
handler.removeCallbacks(runnable);
} catch (Exception e) {
FileLog.e("tmessages", e);
}
}
public void postRunnable(Runnable runnable) {
postRunnable(runnable, 0);
}
public void postRunnable(Runnable runnable, long delay) {
try {
syncLatch.await();
if (delay <= 0) {
handler.post(runnable);
} else {
handler.postDelayed(runnable, delay);
}
} catch (Exception e) {
FileLog.e("tmessages", e);
}
}
public void cleanupQueue() {
try {
syncLatch.await();
handler.removeCallbacksAndMessages(null);
} catch (Exception e) {
FileLog.e("tmessages", e);
}
}
@Override
public void run() {
Looper.prepare();
handler = new Handler();
syncLatch.countDown();
Looper.loop();
}
}
以及调用者:
globalQueue.postRunnable(new Runnable() {
@Override
public void run() {
/* do here what you want */
}
});
你应该检查 Handler 和 Looper
Handlers 默认使用 dispatch_get_main_queue(),你可以发布任何代码块(Runnable 实例)。同样的方法也可以通过 Context.runOnUiThread() 和 View.post(Runnable) 实现。
默认构造函数将继承当前线程的 Looper 实例 (RunLoop 在 iOS 中),并在 Looper 上排队 Runnable 实例 (通过 handlerInstace.post...() 方法)。
对于更复杂的用法,你可以创建自己的 Looper 实例 (请注意,这有点棘手 :))。但这可能会很方便...
此外,对于 Android 我发现 Handlers 是最好的工具之一 (我在 iOS 上也很想念它们),用于应用程序内部的消息传递 (我猜这是进程间通信)。可以自定义处理已发布的消息,等等...