Handler:是android消息机制的核心。一个线程可以有多个handler,但是只能有一个Looper和MessageQueue。handler是用来在线程间传递消息的。
而handler是发送消息以及传递消息的。在UI线程也是主线程,由于主线程会自动创建Looper,所以在子线程中,必须自己创建Looper才能创建Handler。
Handler的消息发送可以是handler.sendMessage()或者是handler.post(Runnable)。其中sendMessage()方法需要实现Handler的handleMessage方法,也就是消息的最终处理。
Looper是运行在创建Handler的那个线程中的。由于可以有多个handler,那么怎么知道消息的最终处理是交给那个handler的handleMessage中呢?
由于Message类中有个变量叫做target,message.target对应生成该message的handler,所以放在Looper处理时,就会转到对应的handleMessage中。
MessageQueue:是消息队列,但是它的实现是单链表,因为是要删除和添加,所以单链表的实现比较好,MessageQueue是由Looper.prapare()中实现的,其实也是Looper.parpare()方法调用Looper构造函数,由Looper构造函数中生成MessageQueue的。MessageQueue有两个方法,一个是enqueueMessage(),一个是next(),enqueueMessage()方法是插入Message,next()方法是读取一个Message,并且删除这个Message。其中next()方法是个无限循环的方法。
Looper:Looper叫做循环,由于MessageQueue只是用来存储Message的,而Looper则是用来处理Message的。Looper.loop()方法调用,才开始真正启动消息循环系统,在loop()中,会不断的调用messagequeue的next()方法,直到next()方法返回null则会停止。而next()不会主动自己返回null的,需要调用MessageQueue的quit()方法或者quitSafely()使得MessageQueue中的next()方法返回null,使得loop()方法中断。
ThreadLocal:不是线程,而是以线程为作用域的,各个线程之间互不干扰的一个数据存储类,用来存储Looper的,其中每个线程都有一个ThreadLocal.Values的变量来存储ThreadLocal的数据,其中是一个table数组。ThreadLocal的好处在于,1.线程之间互不干扰,否则需要设置一个通过handler查找looper的全局hash表。2.用在线程中的函数调用栈深的时候,需要在线程全程传递监听器,可以在该线程中设置一个ThreadLocal的全局变量。
整个流程是:在一般的Android消息机制中,先在主线程中创建一个handler,由于这个handler是在主线程中创建的,所以对应的主线程中本身存在的Looper,在子线程的耗时操作结束以后,需要将这个数据传递给主线程来更新UI,那么就直接调主线程的handler,通过handler.sendMessage()将消息插入到MessageQueue中,再由Looper来提取该消息,并处理,调用msg.target.dispatchMessage(msg),其中msg.target就是对应的handler,只是这个handler.dispatchMessage()方法是在主线程的Looper中执行的。也就实现了从子线程到主线程的传递。其中的MessageQueue和Looper都是主线程的。
以下是handler的实例
其中项目地址为:点击打开链接
package com.example.simmucheng.handlerdemo;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
private Button Btn_start_sendmessage=null;
private Button Btn_start_Runable=null;
private Button Btn_from_main_to_thread=null;
private Button Btn_stop=null;
private TextView Tv_showtextview=null;
private Handler ThreadHandler;
Handler handler_main=new Handler();
Handler handler_main_handlemessage=new Handler(){
@Override
public void handleMessage(Message msg) {
// ThreadHandler.sendMessage(msg);
Tv_showtextview.append("sendMessage = "+msg.arg1);
}
};
Runnable MyRunnable=new Runnable() {
@Override
public void run() {
Tv_showtextview.append("\nloading");
handler_main.postDelayed(MyRunnable,1000);
}
};
Handler handler1=new Handler(){
@Override
public void handleMessage(Message msg) {
Tv_showtextview.append("\nheihei");
Toast.makeText(MainActivity.this,"tttttt",Toast.LENGTH_SHORT).show();
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
new MyThread().start();
Btn_start_Runable.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
handler_main.post(MyRunnable);
}
});
Btn_start_sendmessage.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
new Thread(){
@Override
public void run() {
Message msg=new Message();
msg.arg1=1;
msg.what=2;
handler1.sendMessage(msg);
}
}.start();
}
});
Btn_stop.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
handler_main.removeCallbacks(MyRunnable);
}
});
Btn_from_main_to_thread.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Message msg1=new Message();
msg1.arg1=3;
ThreadHandler.sendMessage(msg1);
}
});
}
private void initView() {
Btn_start_sendmessage= (Button) findViewById(R.id.Start_Handler_sendmessage);
Btn_from_main_to_thread= (Button) findViewById(R.id.from_main_to_thread);
Btn_start_Runable= (Button) findViewById(R.id.Start_Handler_Runable);
Btn_stop= (Button) findViewById(R.id.stop);
Tv_showtextview= (TextView) findViewById(R.id.ShowTextView);
}
class MyThread extends Thread{
@Override
public void run() {
Looper.prepare();
ThreadHandler=new Handler(Looper.myLooper()){
@Override
public void handleMessage(Message msg) {
msg.arg1+=1000;
Message msg1=handler_main_handlemessage.obtainMessage();
msg1.arg1=msg.arg1;
handler_main_handlemessage.sendMessage(msg1);
// 这个里面,在sendMessage(message)之后,会标记该message的isInUse=true
//所以要想再次sendMessage该message,需要重新obtainMessage得到新的message,这样
//得到的message的isInUse会被取消
}
};
Looper.loop();
}
}
}
其中enqueueMessage的局部代码,显示会将message标记为已经加入队列。所以有的时候不注意会出现in use的错误。
boolean enqueueMessage(Message msg, long when) {
if (msg.target == null) {
throw new IllegalArgumentException("Message must have a target.");
}
if (msg.isInUse()) {
throw new IllegalStateException(msg + " This message is already in use.");
}
synchronized (this) {
if (mQuitting) {
IllegalStateException e = new IllegalStateException(
msg.target + " sending message to a Handler on a dead thread");
Log.w(TAG, e.getMessage(), e);
msg.recycle();
return false;
}
<span style="color:#ff0000;">msg.markInUse();</span>
msg.when = when;
Message p = mMessages;
}
}
/*package*/ boolean isInUse() {
return ((flags & FLAG_IN_USE) == FLAG_IN_USE);
}
/*package*/ void markInUse() {
flags |= FLAG_IN_USE;
}