Objective
It is believed that every Android developer knows that the update UI can only be done in the main thread, and that if you need to update the UI after the child thread executes the task, you need to use handler to jump to the main thread. Here are several ways to manipulate the UI.
First, the use of Handler handlemessage ()
Construction of Handler
Public Handler () {This
(null, FALSE);
}
Public Handler (Callback Callback, Boolean async) {
if (find_potential_leaks) {
final class<? extends handler& Gt Klass= getclass ();
if (Klass.isanonymousclass () | | Klass.ismemberclass () | | Klass.islocalclass ()) &&
(Klass.getmodifiers () &modifier.static) = = 0) {
log.w (TAG, "the Followinghandler class should be static or leaks might occur: "+
klass.getcanonicalname ());
}
Mlooper = Looper.mylooper ();
if (Mlooper = = null) {
throw new RuntimeException (
"Can" T create handler Insidethread that has not called looper . Prepare () ");
}
Mqueue = Mlooper.mqueue;
Mcallback = null;
}
The visible construct handler needs looper, and no words throw an exception.Looper.myLooper()
will return a Looper object, how to return it, look at the source code
public static Finallooper Mylooper () {return
(Looper) sthreadlocal.get ();
}
Obviously, the myLooper()
Looper object was removed from the threadlocal. So the question is, when are we going to deposit Looper objects into threadlocal? In fact, the mystery lies in Looper.prepare()
the time we call, look at the source code
public static final void prepare () {
if (sthreadlocal.get ()!= null) {
throw new runtimeexception (' Only one looper May is created per thread ");
}
Sthreadlocal.set (New Looper ());
}
It is visible that a new Looper object is created when the Looper object that sthreadlocal takes out is empty.
This shows that you need to call before instantiating a hanlder, Looper.prepare()
or you will throw an exception unless you are building handler in the main thread. The system has built a looper for the main thread at the time it was created.
Creation of message
The most common practice in general is
Message message = new Message ();
Mhandler.sendmessage (message);
But to do so each time need a new message, more waste of space, we can use to obtainMessage();
look at the source code
Public final message Obtainmessage (int what, int arg1, int. arg2, Object obj) {return
Message.obtain (this, what, arg1,a RG2, obj);
}
This method returns Message.obtain(this, what, arg1,arg2, obj)
, which means obtainMessage()
that it is the same as the function, so it can be used directly Message.obtain(this, what, arg1,arg2, obj)
.
Again look at obtain()
the source code
public static message Obtain (Handler h, int what, int. arg1, int arg2, Object obj) {message
M = obtain ();
M.target = h;
M.what = what;
M.ARG1 = arg1;
M.ARG2 = arg2;
M.obj = obj;
return m;
}
Look at the code above, we still have to find obtain's parameterless structure.
public static message obtain () {
synchronized (spoolsync) {
if (sPool!= null) {message
m = sPool;
SPool = M.next;
M.next = null;
m.flags = 0; Clear In-useflag
spoolsize--;
return m;
}
}
return new Message ();
}
It's not hard to see that obtain returns a Message object from the pool of messages, and if the message pool is empty and then creates a new message, it's obtain()
reasonable to get a message for general use.
parameter of message
If you only need to store integer data, use Arg1 and arg2
Any object that is sent to the receiver. When you use a message object to pass messages between threads, if it contains a parcelable struct class (not a class implemented by the application), this field must be Non-null (non-null).
User-defined message code so that the recipient can learn about the message. Each handler contains its own message code, so there is no need to worry about custom messages that conflict with other handlers.
If you need to pass the bundle object, use thesetData(Bundle)
The handler object that receives this message.
Several ways to handle messages
Public Final Boolean SendMessage (Message msg) {return sendmessagedelayed (msg, 0);//Direct call to Sendmessagedelayed (), just no time delay}
Public Final Boolean sendmessagedelayed (Message msg, long Delaymillis) {if (Delaymillis < 0) {Delaymillis = 0;
Return Sendmessageattime (MSG, systemclock.uptimemillis () + delaymillis);//Call Sendmessageattime, current time plus delay time.
public boolean sendmessageattime (Message msg, long Uptimemillis) {MessageQueue queue = Mqueue;
if (queue = = null) {runtimeexception e = new RuntimeException (this + "sendmessageattime () called with no Mqueue");
LOG.W ("Looper", E.getmessage (), E);
return false; return Enqueuemessage (Queue, MSG, uptimemillis);//Call Enqueuemessage, enclose message queue and time} private Boolean enqueuemessage (Messag
Equeue queue, Message msg, long uptimemillis} {msg.target = this;
if (masynchronous) {msg.setasynchronous (true);
Return Queue.enqueuemessage (msg, uptimemillis);//The Last Call queue's Insert message method, only the time of insertion is made. }
Through the analysis above, no matter which method the handler calls, the sendMessage()
end is to insert the message into the queue, there is no other action. queue.enqueueMessage(msg, uptimeMillis
in this way we also know that the order in which looper processes messages is polling based on how quickly the message is inserted.
How to add empty messages
Public final Boolean sendemptymessage (int what) {return
sendemptymessagedelayed (what, 0);
}
Public final Boolean sendemptymessagedelayed (int what, long Delaymillis) {
msg = Message.obtain ();
Msg.what = what;
Return sendmessagedelayed (msg, delaymillis);
Second, Handler post () method
Use steps
Handler.post (New Runnable () {
@Override public
Void Run ()
is available for UI operations.
}
});
Look at the Post method of the source code
Public Final Boolean post (Runnable R) {return
sendmessagedelayed (Getpostmessage (R), 0);
}
See here is not an epiphany, the original post method is actually sent a message.
Again look at getPostMessage(r)
the source code
Private Final Message Getpostmessage (Runnable r) {message
m = Message.obtain ();
M.callback = R;
return m;
}
This is clear, this method encapsulates the Runnable object as a message, and then sendmessagedelayed sends the past to handler processing.
Here we have to know how the message was taken out, the current MessageQueue exist Mmessages (that is, the message to be processed), and then take the message out, and then let the next message become mmessages, otherwise enter a blocking state, until there is a new message to the team. Whenever a message is taken out, it is passed to the Msg.target dispatchMessage()
, which msg.target
is the statement in the handler Enqueuemessage method msg.target = this
, the current handler object. So the next point is naturally back todispatchMessage()
public void DispatchMessage (message msg) {
if (msg.callback!= null) {
handlecallback (msg);
} else {
if ( Mcallback!= null) {
if (Mcallback.handlemessage (msg)) {return
;
}
}
Handlemessage (msg);
}
If a method is called, the Handler.post()
callback != null
method is executed handleCallback(msg);
Private final void Handlecallback (Message message) {
message.callback.run ();
}
That is, the final Runnable object is handle processed. According to the handler principle, handler needs to instantiate the main thread post method before updating the UI.
The Post method of view
Look at the source code
public Boolean post (Runnable action) {
Handler Handler;
if (mattachinfo!= null) {
handler = Mattachinfo.mhandler;
} else {
viewroot.getrunqueue (). Post (action);
return true;
}
Return Handler.post (action);
}
At a glance, calling the Handlerd post method is essentially the same.
Iv. the Runonuithread () method in activity
Public final void Runonuithread (Runnable action) {
if (Thread.CurrentThread ()!= muithread) {
mhandler.post ( action);
} else {
action.run ();
}
}
This method must have nothing to say, if the UI thread, direct run, not the words with the help ofhandler.post()
One thing to note is that this method only works in the activity.
Summarize
The above is the entire content of this article, I hope to be able to learn or work can bring some help, if you have questions you can message exchange.