Android通过Looper、Handler来实现消息循环机制。Android的消息循环是针对线程的,每个线程都可以有自己的消息队列和消息循环。本文通过几个简单的例子来说明一下Android消息机制的基本使用方法。(本文所有的例子都是基于Android Studio 2.2.3)
一、自定义消息处理机制
首先定义一个子线程,实现消息队列和消息循环,这个子线程的具体实现如下:
/* 定义一个子线程,实现消息队列和消息循环 */
class MyThread extends Thread{
private Looper looper = null;
@Override
public void run() {
super.run();
Looper.prepare(); // 创建消息队列
/* 同步代码块,获得当前线程的Looper对象 */
synchronized (this){
looper = 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() && looper == null) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
return looper;
}
}
并在这个子线程中实现了一个public方法getLooper(),用来和具体的handler进行绑定。在主线程中添加一个按钮,每次按下按钮就向子线程发送一条消息,整个例子完整的代码如下所示:
package cn.edu.syau.yl_app_handler_msg;
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.View;
import android.widget.Button;
public class MainActivity extends AppCompatActivity {
private final String KEY = "MESSAGE";
private Button button = null;
private MyThread thread = null;
private Handler handler = null;
/* 定义一个子线程,实现消息队列和消息循环 */
class MyThread extends Thread{
private Looper looper = null;
@Override
public void run() {
super.run();
Looper.prepare(); // 创建消息队列
/* 同步代码块,获得当前线程的Looper对象 */
synchronized (this){
looper = 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() && looper == null) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
return looper;
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button = (Button) findViewById(R.id.btnSend);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Message message = handler.obtainMessage();
Bundle bundle = new Bundle();
bundle.putString(KEY, "TECH-PRO!");
message.setData(bundle);
handler.sendMessage(message);
System.out.println("main to child : send a message!");
}
});
/* 启动子线程,进行消息循环,接收主线程发送过来的消息 */
thread = new MyThread();
thread.start();
/* 将这个handler和子线程进行绑定,处理子线程接收到的消息 */
handler = new Handler(thread.getLooper(), new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
Bundle bundle = msg.getData();
String string = bundle.getString(KEY);
System.out.println("child from main : " + string);
return false;
}
});
}
}
编译运行,结果如下:
二、实现主线程向子线程发送消息
实现和上面同样的功能,但是使用系统自带的HandlerThread类,它里面已经创建了消息队列并且实现了消息循环,使用起来简单高效,完整的测试代码如下所示:
package cn.edu.syau.yl_app_handler_msg;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
public class MainActivity extends AppCompatActivity {
private final String KEY = "MESSAGE";
private Button button = null;
private HandlerThread handlerThread = null;
private Handler handler = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button = (Button) findViewById(R.id.btnSend);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Message message = handler.obtainMessage();
Bundle bundle = new Bundle();
bundle.putString(KEY, "TECH-PRO!");
message.setData(bundle);
handler.sendMessage(message);
System.out.println("main to child : send a message!");
}
});
/* 启动子线程,进行消息循环,接收主线程发送过来的消息 */
handlerThread = new HandlerThread("TECH-PRO");
handlerThread.start();
/* 将这个handler和子线程进行绑定,处理子线程接收到的消息 */
handler = new Handler(handlerThread.getLooper(), new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
Bundle bundle = msg.getData();
String string = bundle.getString(KEY);
System.out.println("child from main : " + string);
return false;
}
});
}
}
编译并运行结果如下:
三、实现子线程向主线程发送消息
实现和上面例子相反的功能,因为在Android的主线程或者UI线程中已经默认创建了消息队列,并且实现了消息循环,所以只需要只需要将消息处理handler与主线程进行绑定就可以处理主线程的消息了。为了实现这个功能,还需要实现一个子线程向主线程发送消息,这个子线程的具体实现如下:
/* 定义一个子线程用于发送消息 */
class MyThread extends Thread{
@Override
public void run() {
for(;;) {
Message message = myHandler.obtainMessage();
Bundle bundle = new Bundle();
bundle.putString(KEY, "TECh-PRO!");
message.setData(bundle);
myHandler.sendMessage(message);
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("child to main : send a message!");
}
}
}
整个例子的完整代码如下所示:
package cn.edu.syau.yl_app_handler_msg;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
public class MainActivity extends AppCompatActivity {
private final String KEY = "TECH-PRO";
private MyHandler myHandler = null;
private MyThread myThread = null;
/* 定义一个handler用来处理子线程发给主线程的消息 */
class MyHandler extends Handler{
public MyHandler(){}
public MyHandler(Looper looper){super(looper);}
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Bundle bundle = msg.getData();
String string = bundle.getString(KEY);
System.out.println("main from child : " + string);
}
}
/* 定义一个子线程用于发送消息 */
class MyThread extends Thread{
@Override
public void run() {
for(;;) {
Message message = myHandler.obtainMessage();
Bundle bundle = new Bundle();
bundle.putString(KEY, "TECh-PRO!");
message.setData(bundle);
myHandler.sendMessage(message);
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("child to main : send a message!");
}
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
/* 将主线程和handler消息处理绑定在一起 */
myHandler = new MyHandler(MainActivity.this.getMainLooper());
myThread = new MyThread();
myThread.start();
}
}
编译运行,结果如下: