下面的是个人对handler的一些感想,忘能帮助初学者
handler是什么
handler是android系统提供的一套消息机制的上层接口,使用handler可以轻松地切换任务线程那它可以用来干嘛呢。
当需要在子线程中进行耗时的I/O操作的时候,当耗时任务完成以后,需要在UI上做一些改变,但是在子线程不能访问handler这时就要使用handler。要记住一点,handler不是专门用来更新UI的。
接下来介绍几个概念。
MessageQueue
它是用来存储消息的,注意它是单链表的数据结构。
Looper
消息循环者,用来取MessageQueue的消息并处理,没消息阻塞。
好了,接下来慢慢介绍。
不知大家注意到了没子线程访问UI会报异常,这是因为不能再子线程更新UI,那么android是怎么确定的呢,因为ViewRootImpl会对UI操作进行验证,是由ViewRootImpl的checkThread来完成的。因此大家也别想着用什么办法绕过了,因为系统已经强制规定了。
Handler在创建的时候会用当前线程的Looper来构建消息循环系统,因此在子线程中直接使用Handler会报错,因为子线程是没有Looper的,那UI线程有没有呢,UI线程会在ActivityThread创建UI线程的时候初始化一个Looper,这也是主线程可以使用handler的原因,要在子线程使用handler,要先出初始化Looper,调用Looper.perpar()即可当调用handler的send方法时,它会调用MessageQueue的enqueueMessage()方法将消息放到队列中去,Looper发现有新消息时会处理消息,最终消息中的Runnable或者handler的handleMessage会调用。
这里要知道Looper是存储在ThreadLocal中的,它是一个作用域为当前线程的存储类。底下是个例子
public class TestHandlerActivity extends AppCompatActivity {
private static final String TAG = "TestHandlerActivity";
private Handler mHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
//获得刚才发送的Message对象,然后在这里进行UI操作
Log.e(TAG,"------------> msg.what = " + msg.what);
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_handler_test);
initData();
}
private void initData() {
//开启一个线程模拟处理耗时的操作
new Thread(new Runnable() {
@Override
public void run() {
SystemClock.sleep(2000);
//通过Handler发送一个消息切换回主线程(mHandler所在的线程)
mHandler.sendEmptyMessage(0);
}
}).start();
}
这是一个很简单的例子,接下来再看用post方法发送已个Runnable接口的方法。
public class MainActivity extends Activity {
private TextView text_view = null;
private Button start = null;
private Button end = null;
//使用handler时首先要创建一个handler
Handler handler = new Handler();
//要用handler来处理多线程可以使用runnable接口,这里先定义该接口
//线程中运行该接口的run函数
Runnable update_thread = new Runnable()
{
public void run()
{
//线程每次执行时输出"UpdateThread..."文字,且自动换行
//textview的append功能和Qt中的append类似,不会覆盖前面
//的内容,只是Qt中的append默认是自动换行模式
text_view.append("\nUpdateThread...");
//延时1s后又将线程加入到线程队列中
handler.postDelayed(update_thread, 1000);
}
};
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
text_view = (TextView)findViewById(R.id.text_view);
start = (Button)findViewById(R.id.start);
start.setOnClickListener(new StartClickListener());
end = (Button)findViewById(R.id.end);
end.setOnClickListener(new EndClickListener());
}
private class StartClickListener implements OnClickListener
{
public void onClick(View v) {
// TODO Auto-generated method stub
//将线程接口立刻送到线程队列中
handler.post(update_thread);
}
}
private class EndClickListener implements OnClickListener
{
public void onClick(View v) {
// TODO Auto-generated method stub
//将接口从线程队列中移除
handler.removeCallbacks(update_thread);
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}
}
接下来各自分析一下
MessageQueue
它主要用来存储消息,有两个基本操作,插入和读取,读取操作会伴随着删除操作,当Handler发送一条消息时会调用他的enqueueMessage方法插入消息,此时有了一条消息,接着它会调用自身的next方法读取消息并从队列中(数据结构是单链表)删除消息,接着Looper发现有消息就会把它交给handler去处理,handler调用自身的handlermessage()方法,这里要注意我们可以通过getMainLooper()得到UI现成的Looper,当在子线程创建Looper不用的时候要调用他的quitsafely()方法,否则Looper会一直阻塞。
好了,这就是消息处理机制了。