- Docs
- Description
- Message
Defines a message containing a description and arbitrary data object that can be sent to a Handler, including:
- what: message code
- arg1, arg2, obj, data: arguments or data bound with this message, 'obj' is type of Object, while 'data' is type of Bundle
- when: when to dispatch message (immediate or delay)
- replayTo: Messenger indicates where replays to this message can be sent
- target: Handler that will receive this message.
- callback: Runnable that will be executed when this message is handled.
- next: All messages are organized in to a list via this field
Difference between Message.obtain()/Handler.obtain & new Message()
- obtain() will re-use message in pool, (Message that has been processed will be added to pool, the size of pool is 10 in Android 3.0), if there is no message object in pool, create a new one by 'new Message()'
- 'new Message()' always create a new one.
- MessageQueue
Low-level class holding the list of messages to be dispatched by a Looper, but the message that Message.when is not up will delay to be dispatched. MessageQueue ornagizes messages to a pool via Message.next in ascending order by sending time and Message.when.
- Looper
Class used to run a message loop for a thread. Threads by default do not have a message loop associated with them; to create one, call prepare() in the thread that is to run the loop, and then loop() to have it process messages until the loop is stopped.
The task of loop() is:
while()
{
Get a message from MessageQueue via MessageQueue.next(). If MessageQueue is empty, or all message need to be delayed, this methos will block,
Dispatch the message to Handler to process by invoking Handler.dispatchMessage
Recycle the message
}
About quit(): Flow
1) When to invoke Looper.quit(), a message with target being null is added to MessageQueue, and set MessageQueue.mQuiting to be true
2) In Looper.loop(), if the target of new message is null, this method returns.
Note: If you already invoked Looper.loop(), the following invoking Handler.sendMessage/postMessage will cause an RuntimeException (sending message to a Handler on a dead thread)
- Handler
A Handler allows you to send and process Message and Runnable objects associated with a thread's MessageQueue. Each Handler instance is associated with a single thread and that thread's message queue. When you create a new Handler, it is bound to the thread / message queue of the thread that is creating it -- from that point on (You can explicitly specify on what thread / message queue to run at creating time via invoking 'new Handler(Looper)'), it will deliver messages and runnables to that message queue and execute them as they come out of the message queue.
The task of dispatchMessage()
if (message.callback != null)
{
message.callback.run();
}
else
{
handleMessage(xxx);
}
When posting or sending to a Handler, you can either
allow the item to be processed as soon as the message queue is ready, or specify a delay before it gets processed or absolute time for
it to be processed. The latter two allow you to implement timeouts,
ticks, and other timing-based behavior.
By default, handler runs in main thread, no matter whare you create teh instance of Handler, ie:
Handler handler = new MyHandler(); //This handler runs on main thread no matter it is created in main thread, or in addition thread while the thread has no looper.
You can specify that a handler to runs in non-main thread:
HandlerThread thread = new HandlerThread(xxx);
thread.start();
Handler handler = new MyHandler(thread.getLooper()); //Then the handler runs in addition thread.
or
class MyThread extends Thread
{
public void run()
{
Looper.prepare();
Handler handler = new MyHandler(); //The handler runs in MyThread
Looper.loop();
}
}
If you create a Handler object without Looper specified, the Handler is running on the Looper of the thread in which Handler is created; So if the thread has no Looper, an exception will be threw if you create a Handler object in such thread. If you create a Handler object with Looper specified, the Handler is running on the specified Looper, specifically, if you want the Handler to run on the Looper of main thread, you can create it with looper Looper.getMainLooper().
- xxx
- Work Flow
- Create Message: Message.obtain()/Handler.obtain()
Obtain a Message from Message.mPool if the pool is not empty, otherwise, create a new one by invoking 'new Message()'
- Send Message: MessageQueue.enqueueMessage()
Call Message.sendToTarget/Handler.sendMessage()/Handler.postMessage() to add message into MessageQueue.
- Get New Message: MessageQueue.next()
Looper get next Message from MessageQueue by invoking MessageQueue.next() (this message is removed from MessageQueue),
- Dispatch Message: Handler.dispatchMessage
Once Looper get the next message, it will dispatch the message to Handler via Handler.dispatchMessage
- Handle Message
Handler call Message.callback.run() if the callback is not null, otherwrise, call Handler.handleMessage() - Recycle Dispatched Message: Message.recycle()
Then Looper call Message.recycle() to add the Message to Message.mPool if the pool is not full (not exceed size limitation)
- xxx
- When to use Handler
In multiple Threads environment
- Some objects are not thread-safe, such as View in Android. Even if accessing these objects in the same thread as that of Handler, we'd better to sendMessage to Handler, since Handler can make sure to access the objects in sync way. By the way, Handler is thread safe.
- Even if all objects are thread-safe, but we want to access the objects in sync way and want't to sync by myselves.
- xxx
阅读(2062) | 评论(0) | 转发(0) |