Android消息处理机制
相关源码路径:
frameworks/base/core/java/android/os/Looper.java
frameworks/base/core/java/android/os/Handler.java
frameworks/base/core/java/android/os/HandlerThread.java
frameworks/base/core/java/android/os/Message.java
libcore/libart/src/main/java/java/lang/Thread.java
一、消息处理机制基本流程
主线程:
- 创建、启动子线程
- 构造Handler,包含要发送给子线程的消息和消息的处理函数
- 发送消息:Handler.sendMessage, sendEmptyMessageAtTime, sendMessageDelayed
子线程:
- 创建消息队列 MessageQueue –> Looper.perpare();
- 使用Looper循环处理消息 –> Looper.loop();
二、多线程编程
Thread类有多种构造方法
1.实现Runnable接口,run方法在线程启动后运行:
class MyRunnable implements Runnable {
public void run () {
int count = 0;
for (;;) {
Log.d(TAG, "MyThread1 "+count);
count++;
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
2.创建并启动线程myThread1:
myThread1 = new Thread(new MyRunnable(), "MessageTestThread");
myThread1.start();
三、消息处理(自己的线程类)
1.编写自己的线程类
class MyThread extends Thread {
private Looper mLooper;
@Override
/* run方法在线程start后执行 */
public void run() {
super.run();
Looper.prepare();/* 创建消息队列*/
/* 防止myThread2.start后,还没run起来就去执行new Handler,导致getLooper出错,这里仿造HandlerThread的方法*/
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Looper.loop();/* 循环处理消息 */
}
/* mLooper是创建Handler需要的参数 */
public Looper getLooper(){
if (!isAlive()) {
return null;
}
// If the thread has been started, wait until the looper has been created.
synchronized (this) {
while (isAlive() && mLooper == null) {
try {
wait();
} catch (InterruptedException e) {
}
}
}
return mLooper;
}
}
在onCreate中创建、启动线程myThread2:
myThread2 = new MyThread();
myThread2.start();
- 构造Handler,包含要发送给子线程的消息和消息的处理函数
/* 参数是:Handler要发送的目标线程的Looper和消息的处理函数 */
mHandler2 = new Handler(myThread2.getLooper(), new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
Log.d(TAG, "get Message for Thread2 ");
return false;
}
});
3.再button中发送消息
Message msg = new Message();
mHandler2.sendMessage(msg);
sendMessage的实现:
public final boolean sendMessage(Message msg)
{
return sendMessageDelayed(msg, 0);
}
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) {
/* 最终将消息发送到mQueue队列中 */
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);
}
mQueue在构造Handler的时候被赋值,所以消息将发送到线程的looper对应的消息队列中:
mHandler2 = new Handler(myThread2.getLooper(), new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
Log.d(TAG, "get Message for Thread2");
return false;
}
});
==>
public Handler(Looper looper, Callback callback) {
this(looper, callback, false);
}
==>
public Handler(Looper looper, Callback callback, boolean async) {
mLooper = looper;
/* 传进来的线程的looper.mQueue */
mQueue = looper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
四、消息处理(HandlerThread线程类)
1.在onCreate中创建、启动线程myThread3:
myThread3 = new HandlerThread("MessageTestThread3");
myThread3.start();
- 构造Handler,包含要发送给子线程的消息和消息的处理函数
mHandler3 = new Handler(myThread3.getLooper());
- 发送消息(post方法)
mHandler3.post(new Runnable() {
@Override
public void run() {
Log.d(TAG, "get Message for Thread3 "+ mMessageCount);
mMessageCount++;
}
});
完整代码:
package com.thisway.app_addons_0001_message;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Button;
import android.view.View;
import android.util.Log;
import android.os.HandlerThread;
public class MainActivity extends AppCompatActivity {
private Button mButton;
private final String TAG="MessageTest";
private int ButtonCount = 0;
private Thread myThread1;
private MyThread myThread2;
private Handler mHandler2;
private Handler mHandler3;
private int mMessageCount = 0;
private HandlerThread myThread3;
class MyRunnable implements Runnable {
public void run () {
int count = 0;
for (;;) {
Log.d(TAG, "MyThread1 "+count);
count++;
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class MyThread extends Thread {
private Looper mLooper;
@Override
public void run() {
super.run();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Looper.loop();
}
public Looper getLooper(){
if (!isAlive()) {
return null;
}
// If the thread has been started, wait until the looper has been created.
synchronized (this) {
while (isAlive() && mLooper == null) {
try {
wait();
} catch (InterruptedException e) {
}
}
}
return mLooper;
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mButton = (Button)findViewById(R.id.button);
mButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
// Perform action on click
Log.d(TAG, "Button: Send Message "+ ButtonCount);
ButtonCount++;
Message msg = new Message();
mHandler2.sendMessage(msg);
mHandler3.post(new Runnable() {
@Override
public void run() {
Log.d(TAG, "get Message for Thread3 "+ mMessageCount);
mMessageCount++;
}
});
}
});
myThread1 = new Thread(new MyRunnable(), "MessageTestThread");
myThread1.start();
myThread2 = new MyThread();
myThread2.start();
mHandler2 = new Handler(myThread2.getLooper(), new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
Log.d(TAG, "get Message for Thread2");
return false;
}
});
myThread3 = new HandlerThread("MessageTestThread3");
myThread3.start();
mHandler3 = new Handler(myThread3.getLooper());
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
最后附上一些深入的帖子:
Android应用程序消息处理机制(Looper、Handler)分析