1.Handler概述
Handler 可以将一个任务切换到Handler所在线程中去执行,Handler的主要作用是更新UI,有时候需要在子线程进行耗时的I/O操作(读取文件或者访问网络),当耗时任务完成后,需要在UI线程中做一些改变,由于我们不能在子线程中访问UI控件,否则会发生异常,通过Handler就可以将跟新UI操作切换到主线程中执行。
2.Handler机制
注意:子线程中默认是没有Looper的,如果要使用Handler就必须为子线程创建Looper。如果当前线程没有Looper就会报错,Can’t create handler inside thread that has not called Looper.prepare()
主线程(UI线程)即是ActivityThread,ActivityThread被创建时会初始化Looper,所以在主线程中直接可以使用Handler。
Android消息机制主要是指Handler的运行机制及Handler所附带的MessageQueue和Looper的工作过程
Android中访问UI只能在主线程中进行,如果在子线程中访问UI,就会抛出异常,Handler解决了在子线程中无法访问UI的矛盾。
系统为什么不容允许在子线程中访问UI?
Android的UI控件不是线程安全的,在多线程中并发访问可能出现问题。
Handler的工作过程
Handler的send方法被调用时,它会调用MessageQueue的enqueueMessage方法,将消息放入消息队列中,当Looper发现有新消息来时,就会处理这个消息,最终Handler的handleMessage方法就会被调用
3.Android消息机制分析
(1)ThreadLocal的工作原理
ThreadLocal是一个线程内部的数据存储类,通过它可以在指定线程中存储数据,数据存储以后,只有在指定的线程中获取到存储数据,对于其他线程来说则无法获取到数据。
可能还是不太好理解,下面直接上代码
运行结果截图:
可以看出不同线程访问的是同一个ThreadLocal,但是它们通过ThreadLocal获取的值却不一样。
主线程设置的是true,所以获取到的是true
第一个子线程设置的是false,所以获取到的是false
第二个子线程没有设置,所以获取到的是null
(2)消息队列MessageQueue的工作原理
MessageQueue:消息队列,内部实现是通过一个单链表的数据结构来维护消息列表
eqeueMessage:就是向单链表中插入数据。
next:是一个无线循环的方法,如果没有消息,next方法就一直阻塞在这了
如果有消息,next方法就返回这条消息并将消息从单列表中移除。
(3)Looper的工作原理
Looper扮演者消息循环的角色,不停的从消息队列MessageQueue中查看是否具有消息,如果有消息就会立刻处理,否则就一直阻塞在那里
Handler中需要Looper,没有Looper线程就会报错,通过Looper.prepare()就可以为当前线程创建一个Looper,通过Looper.loop()来开启消息循环
下面以代码来演示,如果子线程中没有创建Looper就会报错,直接上代码:
package com.zhoujian.handler;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.widget.Button;
public class MainActivity extends Activity
{
private static final String TAG = "MainActivity";
private Handler mHandler;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button bt_send = (Button) findViewById(R.id.bt_send);
bt_send.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v)
{
Message msg = mHandler.obtainMessage();
mHandler.sendMessage(msg);
}
});
new Thread()
{
@Override
public void run()
{
mHandler = new Handler()
{
@Override
public void handleMessage(Message msg)
{
super.handleMessage(msg);
Log.i(TAG, "收到了主线程发来的消息");
}
};
}
}.start();
}
}
报错信息:
正确的代码:
4.最后来一个简单的Handler实例
直接上代码:
package com.zhoujian.handler;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
public class MainActivity extends Activity
{
private static final String TAG = "MainActivity";
private static final int SEND_MESSAGE_FLAG = 1;
private Button bt_send;
private TextView tv_message;
Handler mHandler = new Handler()
{
private Bundle mData;
@Override
public void handleMessage(Message msg)
{
super.handleMessage(msg);
switch (msg.what)
{
case SEND_MESSAGE_FLAG:
mData = msg.getData();
String name = mData.getString("name");
String sex = mData.getString("sex");
tv_message.setText(msg.obj.toString());
//tv_message.setText(name+" : "+sex);
break;
}
}
};
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
clickEvent();
}
private void clickEvent()
{
bt_send.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v) {
new Thread()
{
public void run()
{
// 在此执行耗时工作,执行完毕后调用handler发送消息
try
{
//睡眠1秒 模拟执行耗时任务
Thread.sleep(1000);
//发送消息
Message message= Message.obtain();
message.what=SEND_MESSAGE_FLAG;
Bundle mBundle = new Bundle();
mBundle.putString("name","周建");
mBundle.putString("sex","男");
message.setData(mBundle);
//mHandler.sendMessage(message);
mHandler.obtainMessage(SEND_MESSAGE_FLAG,"消息来啦") .sendToTarget();
}
catch (Exception e)
{
e.printStackTrace();
}
}
}.start();
}
});
}
private void initView()
{
bt_send = (Button) findViewById(R.id.bt_send);
tv_message= (TextView) findViewById(R.id.tv_message);
}
}
运行结果截图: