1. Browser's thread
There are two threads in Browser's application.
One is the UI thread, the activity's thread, and the other is the WebCoreThread.
No matter how many tabs you open, there is still one BrowserActivity and one WebCoreThread.
so there are always 2 thread in Browser's aplication.
2.WebCoreThread
WebCoreThread was first created in WebViewCore's constructor function
synchronized (WebViewCore.class) {
if (sWebCoreHandler == null) {
// Create a global thread and start it.
Thread t = new Thread(new WebCoreThread());
t.setName(THREAD_NAME);
t.start();
try {
WebViewCore.class.wait();
} catch (InterruptedException e) {
Log.e(LOGTAG, "Caught exception while waiting for thread " +
"creation.");
Log.e(LOGTAG, Log.getStackTraceString(e));
}
}
since WebCoreHandler is a static member of WebViewCore, this code will only executed once.
as new WebViewCore's object is creating the sWebCoreHandler will not be null.
3. WebViewCore's handler
there are two handlers in WebViewCore,
// EventHub for processing messages
private final EventHub mEventHub;
// WebCore thread handler
private static Handler sWebCoreHandler;
....
private Handler mHandler;
one is sWebCoreHandler which we mentioned above and the other is mEventHub's mHandler.
4. Handler' Queue
We know all Handler send message to a Queue. And how we can know our handler's target Queue?
The handler's queue is the thread's queue that create the Handler using "public Handler()".
except you assign a looper to it using another form of construcor "public Handler(Looper looper)", in the case the handle will share the queue with the looper.
5. Looper's Queue
we know a Looper do the opposite thing as the Handler, it get the message from a queue and loop it?
How is the Queue comes? usually it the looper to create the Queue, using looper's prepare(), it will create a new message Queue.
6. Queue's thread
How can we know which thread will loop queue's message?
it's depend on the queue's looper. The thread call the Looper's loop(), will loop the queue's message.
usually we create the handler and prepare the looper in one thread.
Generally speaking in which thread the handler's constructor is called, in which the handler's handlerMesssage() will be called.
As we mentioned in item 3, so bothe sWebCoreHandle and mEventHub's mHandler will be working in WebViewCore's thread.
7. dump a queue
the function was defined in MessageQueue.java
public void dumpQueue_l()
{
Message p = mMessages;
System.out.println(this + " queue is:"+"now is"+SystemClock.uptimeMillis());
while (p != null) {
System.out.println(" " + p);
p = p.next;
}
}
it was commented, we just need to activie it
a. dump a messQueue of a Handler
myandler.getLooper().myQueue().dumpQueue_l();
b. dump a messQueue of the Current Thread
Looper.myLooper().myQueue().dumpQueue_l();
8.trace a handler
how can we know how many messages and which messages are sent by the hanler.
public boolean sendMessageAtTime(Message msg, long uptimeMillis)
{
boolean sent = false;
MessageQueue queue = mQueue;
if (queue != null) {
msg.target = this;
sent = queue.enqueueMessage(msg, uptimeMillis);
}
else {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
}
return sent;
}
we just need to trace here.
the problem is that the code is runed by too many handler, how can we distinguish our handler?
But we need to add some extra attribute to the handler and do dome judgement in this function.
public int handler mId = 0;
......
public boolean sendMessageAtTime(Message msg, long uptimeMillis)
{
if (mId == LOGID)
Log.d(TAG, "msg="+msg);
boolean sent = false;
MessageQueue queue = mQueue;
if (queue != null) {
msg.target = this;
sent = queue.enqueueMessage(msg, uptimeMillis);
}
else {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
}
return sent;
}
of course we need to set the log property for our handler
such as
mHandler.mId = LOGID
of courece , you can do it more delegant , that just an example.
9. trace a Queue
the same way as abrove
final boolean enqueueMessage(Message msg, long when) {
int pendingIdleHandlerCount = -1; // -1 only during first iteration
.....
if (mId == LOGID)
Log.d(TAG, " msg enqueue="+msg);
.....
}
10. trace a Looper
there will be some difference, since the Looper's loop function is a static function, only static function and members can passed here.
we can't use a static id to distinguish our Looper, it make nonsence because all Looper share the same static id.
But we can use it's queue to do that. Looper.myQueue() is a static function, but will return each Looper's own different Queue.
so we can do that like this.
public static final void loop() {
Looper me = myLooper();
......
Queue queue=myQueue();
if (queue.getId() == IDLOG)
Log.d(TAG, "loop msg="+msg);
.....
}
11, extra
get the current thread's Looper
Looper loop = Looper.myLooper();
get the current thread's Queue
Looper loop = Looper.myLooper().myQueue();
get the current thead's Handler
Since there maybe many handler for the thread, so the code will not know.
But you create the Handler and you will know,
get Looper of the current handler().
Looper loop = mHandler.getLooper();
get the Queue of the current handler();
Looper loop = mHandler.getLooper().myQueue();
that's all.