Handler defines and functions
Handler is a set of message passing mechanism of AndorID. It is used for cross-thread communication. It is mainly used for interaction between worker threads and main threads. UI operations on AndorID need to be performed on the main thread, and are usually performed on other child threads. The result of a time-consuming operation can be used to communicate across threads when the UI line needs to communicate first
Handler Usage Flowchart
The principle diagram of the Handler
A few key classes:
- Message: data unit,
MessageQueue
One by one. - Looper:
MessageQueue
withHandler
Communication middleman. Two functions: continuous cycle fromMessageQueue
Remove theMessage
That will beMessage
Send to the correspondingHandler
. - MessageQueue: Data structure (fifO) storage
Message
- Handler: common middleman between threads,
Message
The logical processor of information willMessage
Sent to theMessageQueue
To deal withLooper
Sent overMessage
Based on using
Public class MainActivity extends appActivity {private static class MyHander extends Handler{private final WeakReference<MainActivity> mActivity ; public MyHander(MainActivity activity){ mActivity = new WeakReference<MainActivity>(activity); } @Override public void handleMessage(Message msg) { super.handleMessage(msg);if(null ! = mActivity.get()) { switch (msg.what){caseMactivity.get ().tonotify ();break;
default:
break;
}
}
}
}
MyHander myHander;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); MyHander = new myHander (this); Button button = findViewById(R.id.btn); button.setOnClickListener(new View.OnClickListener() {@override public void onClick(View v) {myhander.obtainMessage (); message.what = 1; message.obj = getString(R.string.text); myHander.sendMessageDelayed(message,5000); }}); } public voidtoNotify() {... Logical operation}}Copy the code
Key Code 1: MyHanlder inherits Handler key code 2: Create a myHandler object and pass MainActivity into myHandler. MyHandler weakly references MainActivity, so myHandler # handleMessage() requires if (null! = mActivity. The get () do the null object determine key code 3: build a Message that can be obtained from the buffer pool, may also directly bring a new Message, and send the myHander. SendMessageDelayed (5000) the Message,
If you want to write MyHander as an anonymous inner class in MainActivity, you’re risking a memory leak. Because the anonymous inner class refers to the outer class, the outer class is hijacked, which can lead to a memory leak. This prevents the handler from hijacking a reference to the external MainActivity class
Handler sends data in two different forms
sendxxx()
The method of
Take a look at the differences between several methods of source code:
public final boolean sendMessage(Message msg)
{
return sendMessageDelayed(msg, 0);
}
public final boolean sendEmptyMessage(int what)
{
return sendEmptyMessageDelayed(what, 0);
}
public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
Message msg = Message.obtain();
msg.what = what;
return sendMessageDelayed(msg, delayMillis);
}
public final boolean sendEmptyMessageAtTime(int what, long uptimeMillis) {
Message msg = Message.obtain();
msg.what = what;
return sendMessageAtTime(msg, uptimeMillis);
}
public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
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);
}
Copy the code
SendMessageAtTime (Message MSG, long uptimeMillis) is called at the end of each method. Note the difference between sendMessageAtTime(Message MSG, Long uptimeMillis) and sendMessageDelayed(Message MSG, Long delayMillis). One is the current moment, one is the current moment +delayMillis
2. Postxxx () method
public final boolean post(Runnable r)
{
return sendMessageDelayed(getPostMessage(r), 0);
}
public final boolean postAtFrontOfQueue(Runnable r)
{
return sendMessageAtFrontOfQueue(getPostMessage(r));
}
public final boolean postDelayed(Runnable r, long delayMillis)
{
return sendMessageDelayed(getPostMessage(r), delayMillis);
}
public final boolean postDelayed(Runnable r, Object token, long delayMillis)
{
return sendMessageDelayed(getPostMessage(r, token), delayMillis);
}
public final boolean postAtTime(Runnable r, long uptimeMillis)
{
return sendMessageAtTime(getPostMessage(r), uptimeMillis);
}
public final boolean postAtTime(Runnable r, Object token, long uptimeMillis)
{
return sendMessageAtTime(getPostMessage(r, token), uptimeMillis);
}
Copy the code
Instead of using the sendxxx method, look at getPostMessage()
Here’s a pit to remember to look at: Handler.post(Runnable) is basically generating a Message with what = 0. If you call handler. post(Runnable) and then send any Message with what = 0, the original Message will be removed. So see a face meng force specific wait code parsing to see www.cnblogs.com/coding-way/…
The source code parsing
Start with the main thread ~ ####ActivityThread
public final class ActivityThread extends ClientTransactionHandler {
final H mH = new H();
final Handler getHandler() {
return mH;
}
class H extends Handler {
......
public void handleMessage(Message msg) {
if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
switch (msg.what) {
case BIND_APPLICATION:
......
break;
}
case EXIT_APPLICATION:
......
break;
}
}
public static void main(String[] args) {
Process.setArgV0("<pre-initialized>"); . // 1 looper.prepareMainLooper (); . ActivityThread thread = new ActivityThread(); thread.attach(false, startSeq); // Key code 2if(sMainThreadHandler == null) { sMainThreadHandler = thread.getHandler(); }... // 3 looper.loop (); }Copy the code
PrepareMainLooper () key code 2: The mH object implements the handleMessage(Message MSG) method. Looper.loop() starts the loop
Let’s take a look at key code 1 and look at the Looper class and the object’s calling method ()
Looper (partial source code)
public final class Looper {
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
private static Looper sMainLooper; // guarded by Looper.class
final MessageQueue mQueue;
final Thread mThread;
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if(sMainLooper ! = null) { throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
public static void prepare() {
prepare(true);
}
private static void prepare(boolean quitAllowed) {
if(sThreadLocal.get() ! = null) { throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}
public static void loop() {
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread."); } final MessageQueue queue = me.mQueue; .for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return; }... try { msg.target.dispatchMessage(msg); }... }}}Copy the code
Looper.prepareMainLooper()
: Related call flow for this methodprepare(false)
->sThreadLocal.set(new Looper(quitAllowed));
->myLooper()
->sThreadLocal.get()
So here we have onelooper
And set tosThreadLocal
In, the time to get fromsThreadLocal
To obtain. And inprepare(false)
If the method already exists, it cannot be called againOnly one thread can existLooper
And aLooper
You can only have onemQueue
On the other hand, indicateLooper
withMessageQueue
It’s a one-to-one relationshipLooper.loop()
: The related call flow of this methodme
->me.mQueue
– > (for (;;) -> queue.next()->msg.target.dispatchMessage(msg)
) Start the endless cycle of rotation trainingMessageQueue
.msg.target
In fact, the return isHandler
, the use ofHandler
Sending data (about ThreadLocal, more on that later)
Now let’s look at the Handler method that sends the data dispatchMessage
Handler (partial source code)
public class Handler {
public Handler(Looper looper, Callback callback, boolean async) {
mLooper = looper;
mQueue = looper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
public interface Callback {
public boolean handleMessage(Message msg);
}
public void handleMessage(Message msg) {
}
public void dispatchMessage(Message msg) {
if(msg.callback ! = null) { handleCallback(msg); }else {
if(mCallback ! = null) {if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
private static void handleCallback(Message message) {
message.callback.run();
}
public final boolean post(Runnable r)
{
return sendMessageDelayed(getPostMessage(r), 0);
}
public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
Message msg = Message.obtain();
msg.what = what;
return sendMessageDelayed(msg, delayMillis);
}
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}
private static Message getPostMessage(Runnable r, Object token) {
Message m = Message.obtain();
m.obj = token;
m.callback = r;
returnm; }}Copy the code
Here you can see there are three different calls to dispatchMessage(Message MSG)
handleCallback(msg)
: This is processingHandler.postxxx(Runnable r,xx)
The sent information is processed and eventually returned to user
therun
Method inside do logic processinghandleMessage(msg)
withmCallback.handleMessage(msg)
: are used for processingHandler.sendxxx()
The message sent, the difference is, instantiationHandler
Student: Incoming or notmCallback
Object, if anymCallback.handleMessage
Do logical processing, if not inhandleMessage
Logical processing
Take a look at some of the properties of the Message class
Message (partial source)
public final class Message implements Parcelable {
public int what;
public int arg1;
public Object obj;
long when;
Bundle data;
Handler target;
Runnable callback;
Message next;
}
Copy the code
Message owns Handler objects, so messages sent from different Handler objects pass themselves in.
# # #
Handler passes itself to Messag and sends it to MessageQueue. Looper starts the rotation and keeps rotating MessageQueue messages, takes out the Message and uses Handler objects to call back its own methods to perform logical operations. Looper: Is stored in a ThreadLocal variable on the first instantiation, and is returned if there is none, so there is only one Looper per thread. 5. MessageQueue: is created in the constructor of Looper, and as a member variable, a thread has one and only MessageQueue Handler: Multiple threads can be created, there is no limit to how many threads can be created, and they hold handlers inside messages, so different messages can be logically manipulated by their own hijacked handalers
Handler A variety of interview questions
(You can refer to the netizen’s article)blog.csdn.net/feather_wch…