本文共 8160 字,大约阅读时间需要 27 分钟。
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(); }}编译运行,结果如下: