Handler的作用
我们通常总是说Android的UI线程不能处理超过5s的耗时任务,也不能处理网络操作。因为为了性能,设计的时候并没有考虑线程安全(就是多线程操作可能同时更改同一数据从而让结果混乱)。所以限定规则,只能在主线程操作UI组件。那么我们平时开发肯定会涉及后台任务修改UI数据的,那么Handler的消息传递机制就是用其他线程处理事务逻辑,通知主线程修改UI操作的中间人。
Handler、Message、Loop、MessageQueue概念
Message、Loop、MessageQueue这三个就像是Handler的小弟一样,关系要好,缺一不可。
- Handler:其他线程中发送消息、主线程中获取处理消息。
- Message:Handler发送或处理的具体消息对象。
- Looper:每个线程只能有一个Looper,不断从MessageQueue读取消息传递到Handler。
- MessageQueue:消息队列,先进先出的方式管理Message、Looper创建时会绑定与之关联的MessageQueue
四者的关系缺一不可
Handler想要正常工作,需要MessageQueue管理Message,而MessageQueue是由Looper管理的,所以Looper也是必要的。因此他们四个是相辅相成,缺一不可的关系。UI线程系统已经初始化过默认Looper所以我们平常使用未指定Looper也用了Handler是这个原因。但我们如果在自己的线程中就要指定Looper对象了。需压注意的是使用Handler前要先调用prepare()方法实例化Looper。
MessageQueue对象由Looper()方法构建:
private Looper(){
mQueue = new MessageQueue();
mRun = true;
mThread = Thread.currentThread();
}
创建Looper使用它的prepare()方法即可,一个线程只能有一个Looper存在:
public static final void prepare(){
if(sThreadLocal.get() != null){
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper());
}
然后调用Looper.loop()方法运行消息队列。loop()方法执行一个死循环来处理消息队列,如果没有消息进入阻塞状态。
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
// This must be in a local variable, in case a UI event sets the logger
final Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
}
final long traceTag = me.mTraceTag;
if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
}
try {
msg.target.dispatchMessage(msg);
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
if (logging != null) {
logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
}
// 使用final保证分发消息过程中,线程标识符不会被修改
final long newIdent = Binder.clearCallingIdentity();
if (ident != newIdent) {
Log.wtf(TAG, "Thread identity changed from 0x"
+ Long.toHexString(ident) + " to 0x"
+ Long.toHexString(newIdent) + " while dispatching to "
+ msg.target.getClass().getName() + " "
+ msg.callback + " what=" + msg.what);
}
msg.recycleUnchecked();
}
所以我们在子线程中使用Handler处理事务时,只要注意Looper的实例化和Message的处理即可。
Handler实例
自定义线程处理Handler操作:
- 调用Looper.loop()实例化looper对象,looper构造时自动创建MessageQueue对象
- 使用Handler实例化,覆写handleMessage(Message msg)处理自己的事务
- 调用Looper.loop()方法启动消息循环机制
MainActivity.java
public class MainActivity extends AppCompatActivity {
private Button mButton;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//启动线程监听handler消息
final MyThread myThread = new MyThread();
myThread.start();
mButton = (Button) findViewById(R.id.btn_click);
mButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//发送空消息what类型为1,这个无法传递数据,捕获到1既可作相关操作
//myThread.mHandler.sendEmptyMessage(1);
//或者发送Message类型的消息,根据需求选择即可Message可携带的数据类型更丰富
Message message = new Message();
message.what = 1;
Bundle bundle = new Bundle();
bundle.putString("test","hello");
message.setData(bundle);
myThread.mHandler.sendMessage(message);
}
});
}
//自定义线程处理Handler信息
class MyThread extends Thread{
private Handler mHandler;
@Override
public void run() {
//在handler之前调用,保证Looper对象创建好,因为子线程是不会自动帮我们创建Looper对象的
Looper.prepare();
mHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
//获取到消息的what类型
if (msg.what == 1){
//Message 携带消息获取
Bundle result = msg.getData();
String s = result.getString("test");
Toast.makeText(MainActivity.this,s,Toast.LENGTH_SHORT).show();
}
}
};
//循环处理开始
Looper.loop();
}
}
}
布局文件也只是一个按钮,不贴了,运行后点击按钮就可以toast显示出hello字样。
这样处理逻辑我们新开了线程,在里边添加Thread.sleep(8888);模拟耗时操作也不会阻塞主线程引发ANR了。
Handler常用的方法:
- hasMessages(int what) :检查队列中是否含what属性值的消息
- hasMessages(int what, Object object):检查队列是否含指定What属性值且object指定对象的消息
- obtainMessage() :获取消息
- sendEmptyMessage(int what) :发送只含what属性的空消息
- sendMessage(Message msg) :立即发送消息
- sendMessageDelayed(Message msg, long delayMillis):指定多少毫秒后发送消息
- handleMessage(Message msg) :处理收到的消息,通常覆写该方法实现自己的需求