其实非常简单,只要搞清楚Thread、Looper、Handler它们各自的作用就OK了。
- Thread 这个大家都知道就是线程,线程中包括一个消息队列(Message Queue),一个循环处理消息队列中消息的工具(Looper)。
- Looper 这个可能有点陌生,就是Thread中的一个用来开启消息循环的工具,循环的取出Message Queue中的消息来让Thread执行。
- Handler 这个可以看作是Looper的一个接口,具体怎么处理消息是在Handler中定义的(handleMessage()方法中定义)。
知道三者的含义那么就好说,剩下的就是怎么把它们给联系起来,由于Message Queue和Looper都是Thread自带的那么就不需要new出来,主要是Looper有点特殊,就是在使用Looper前必需 调用Looper.prepare()来初始化Thread的Looper,然后调用Looper.loop()来让Looper循环处理Message Queue中的消息(写在Looper.loop()之后的代码不会被执行,这个函数内部应该是一个循环,当调用mHandler.getLooper().quit()后,loop才会中止,其后的代码才能得以运行)。但是怎么向Message Queue中发送消息以及如何处理消息就需要我们自定义了,这就用到了 Handler ,Handler是与Looper绑定的。在调用了Looper.prepare()后,将Handler与Looper绑定就OK了。怎么绑定看下面:
首先明确一下,在android主线程(UI线程)也是一个线程,它里面也有Message Queue、Looper,只是android自动给主线程将Looper设置好了,那么要给主线程通讯我们只需要在主线程 new一个handler:
Handler mHandler = new Handler()//将主线程的Looper与handler绑定;
并且实现它里面的 handleMessage()方法即可(将消息发送给主线程)。
在这里没有看到Looper与Handler的绑定,其实在这个无参构造函数中 有这么句代码:
mLooper = Looper.myLooper();
无参构造函数直接取 当前所在线程的Looper,如果在子线程中没有执行Looper.prepare()方法就调用会报错,因为如果不执行Looper.prepare()方法,Looper还没有初始化。
下面看一个例子就全OK了(是两个子线程之间通信):
public class ServiceTestThreadCommunication extends Service {
private static final String TAG = "ServiceTestThreadCommunication";
Looper mLooper;
ServiceHandler mHandler;
boolean isThread1Ready = false;
Object mLock = new Object();
@SuppressLint("HandlerLeak")
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper){
super(looper);
}
@Override
public void handleMessage(Message msg) {
Log.d(TAG, "当前线程 ==" + Thread.currentThread().getName()
+ "== 接收到来自 ==" + msg.obj.toString() + "== 线程的信息");
ServiceTestThreadCommunication.this.stopSelf();
super.handleMessage(msg);
}
}
@Override
public void onCreate() {
super.onCreate();
ServiceThread1 thread1 = new ServiceThread1("thread1");
ServiceThread2 thread2 = new ServiceThread2("thread2");
thread2.start();
thread1.start();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
}
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
}
@Override
public void onDestroy() {
super.onDestroy();
if(null != mLooper){
mLooper.quit();
}
}
private class ServiceThread1 extends Thread{
public ServiceThread1(String string) {
super(string);
isThread1Ready = false;
}
@Override
public void run() {
synchronized(mLock){
Looper.prepare();
mLooper = Looper.myLooper();
mHandler = new ServiceHandler(mLooper);
isThread1Ready = true;
mLock.notifyAll();
}
Looper.loop();
}
}
private class ServiceThread2 extends Thread{
public ServiceThread2(String string) {
super(string);
}
@Override
public void run() {
while(!isThread1Ready){
synchronized(mLock){
try {
mLock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Message msg = Message.obtain();
msg.obj = getName();
mHandler.sendMessage(msg);
}
}
}
下面再看一个google的例子,是主线程与子线程通信的例子:
public class HelloService extends Service {
private Looper mServiceLooper;
private ServiceHandler mServiceHandler;
// Handler that receives messages from the thread
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
// Normally we would do some work here, like download a file.
// For our sample, we just sleep for 5 seconds.
long endTime = System.currentTimeMillis() + 5*1000;
while (System.currentTimeMillis() < endTime) {
synchronized (this) {
try {
wait(endTime - System.currentTimeMillis());
} catch (Exception e) {
}
}
}
// Stop the service using the startId, so that we don't stop
// the service in the middle of handling another job
stopSelf(msg.arg1);
}
}
@Override
public void onCreate() {
// Start up the thread running the service. Note that we create a
// separate thread because the service normally runs in the process's
// main thread, which we don't want to block. We also make it
// background priority so CPU-intensive work will not disrupt our UI.
HandlerThread thread = new HandlerThread("ServiceStartArguments",
Process.THREAD_PRIORITY_BACKGROUND);
thread.start();
// Get the HandlerThread's Looper and use it for our Handler
mServiceLooper = thread.getLooper();
//在这里Handler是在UI线程中new出来的,但是它与HandlerTread的Looper绑定了,所以
//ServiceHandler中的handleMessage()方法是在HandlerThread这个线程中执行的。
mServiceHandler = new ServiceHandler(mServiceLooper);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show();
// For each start request, send a message to start a job and deliver the
// start ID so we know which request we're stopping when we finish the job
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
mServiceHandler.sendMessage(msg);
// If we get killed, after returning from here, restart
return START_STICKY;
}
@Override
public IBinder onBind(Intent intent) {
// We don't provide binding, so return null
return null;
}
@Override
public void onDestroy() {
Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show();
}
}