Summary of a.
In Android, the main interprocess communication with Binder, Socket, and communication between threads is Android message mechanism, before analyzing the source code, first review how to use.
Two. Traditional use
[-> SecondActivity.java]
package com.dopezhi.handlerdemo;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.widget.Toast;
public class SecondActivity extends AppCompatActivity {
private final String TAG = "SecondActivity";
public final int MSG_GET = 1;
public final int MSG_RESULT = 2;
public Handler mUiHandler = new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(@NonNull Message msg) {
Log.i(TAG, "mUiHandler handleMessage thread : " + Thread.currentThread());
switch (msg.what) {
case MSG_RESULT:
Toast.makeText(getApplicationContext(), (String) msg.obj, Toast.LENGTH_LONG).show();
break;
default:
break; }}};@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
LooperThread looperThread = new LooperThread("looper_thread");
looperThread.start();
findViewById(R.id.get_second).setOnClickListener(v -> {
looperThread.mSubHandler.sendEmptyMessage(MSG_GET);
});
}
class LooperThread extends Thread {
public Handler mSubHandler;
public LooperThread(String name) {
super(name);
}
@Override
public void run(a) {
Looper.prepare();
mSubHandler = new Handler(Looper.myLooper()) {
@Override
public void handleMessage(@NonNull Message msg) {
Log.i(TAG, "mSubHandler handler handleMessage thread : " + Thread.currentThread());
switch (msg.what) {
case MSG_GET:
double number = Math.random();
Message message = new Message();
message.what = MSG_RESULT;
message.obj = "dopezhi : " + number;
mUiHandler.sendMessage(message);
break;
default:
break; }}}; Looper.loop(); }}}Copy the code
Create another thread (looper_thread) in the main thread, initialize Looper in the looper_thread, create mSubHandler for the child thread, and hook to the child thread’s Looper.
Initialize mUIhandler in the main thread, hooked to the main thread Looper.
Click the button, and the main thread sends the message MSG_GET to the child thread. After receiving the message, the child thread sends the message MSG_RESULT to the main thread. Finally, the main thread displays the contents of the message sent by the child thread through Toast.
3. Enclosed wheel -HandlerThread
Why do handlerThreads exist? Looper.prepare, looper. Loop, looper. Loop, looper. prepare, looper. Loop If the main thread wants to get a Looper from the child thread, the child thread may execute looper. prepare to create a Looper, but the child thread may not immediately schedule the Looper and create it.
[-> MainActivity.java]
package com.dopezhi.handlerdemo;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import android.annotation.SuppressLint;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import android.os.MessageQueue;
import android.util.Log;
import android.view.View;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
private final static String TAG = "MainActivity";
protected final int MSG_GET = 1;
protected final int MSG_RESULT = 2;
private HandlerThread mHandlerThread;
// Handler instance in child thread
private Handler mSubTreadHandler;
private Handler mUiHandler = new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(@NonNull Message msg) {
Log.i(TAG, "mUiHandler handleMessage thread : " + Thread.currentThread());
switch (msg.what) {
case MSG_RESULT:
Toast.makeText(getApplicationContext(), (String) msg.obj, Toast.LENGTH_LONG).show();
break;
default:
throw new IllegalStateException("Unexpected value: "+ msg.what); }}};@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.i(TAG, "onCreate thread : " + Thread.currentThread());
// Click the button to send a message to the child thread handler
findViewById(R.id.get).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mSubTreadHandler.sendEmptyMessage(MSG_GET);
Log.i(TAG,"I frist"); }}); findViewById(R.id.jumoToSecond).setOnClickListener(v -> { Intent intent =new Intent();
intent.setClass(this, SecondActivity.class);
startActivity(intent);
});
initHandlerThread();
}
private void initHandlerThread(a) {
// Create the HandlerThread instance
mHandlerThread = new HandlerThread("handler_thread");
// Start the thread
mHandlerThread.start();
// Get the Looper instance in the HandlerThread thread
Looper loop = mHandlerThread.getLooper();
//NEW, the idelHandler execution method is called back to when there is no message in the message queue
Looper.myQueue().addIdleHandler(new MessageQueue.IdleHandler() {
@Override
public boolean queueIdle(a) {
Log.i(TAG,"The queue is empty");
return false; }});// Create a Handler to bind to the thread
mSubTreadHandler = new Handler(loop) {
@Override
public void handleMessage(@NonNull Message msg) {
Log.i(TAG, "mSubThreadHandler handleMessage thread : " + Thread.currentThread());
switch (msg.what) {
case MSG_GET:
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Log.i(TAG,"sorry , I first");
double number = Math.random();
String result = "dopezhi: " + number;
// Send a message to the UI thread to update the UI
Message message = new Message();
message.what = MSG_RESULT;
message.obj = result;
// When the child thread receives the message, it sends it to the main thread Handler
mUiHandler.sendMessage(message);
break;
default:
break; }}}; }}Copy the code
As you can see, starting a child thread and executing the message loop does not require the following steps, just new HandlerThread.start.
[-> HandlerThread.java]
public class HandlerThread extends Thread
public void run(a) {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
Copy the code
If you look at the source code for HandlerThread, which is essentially Thread, you override the run method to initialize Looper and start the Looper loop. If mhanderThread.getLooper () is called before then, wait() until Looper creates the call notifyAll.