【Android基础知识】Handler、Message、Looper的关系
2016-07-12 17:56
513 查看
为什么只能在UI线程进行更新UI
最根本的目的就是为了解决多线程并发问题。假如在一个Activity中,有多个线程去更新UI,并且都没有加锁,那么会产生什么问题?
更新界面错乱
如果对更新UI的操作都进行加锁处理的话又会产生什么问题?
性能下降
为了处理上面的问题,android给我们提供了一套更新UI的handler机制,我们不用关心多线程问题,只需要去遵循这样的机制就可以了。
Handler的基本概念
提供了异步的线程处理。
有很多的操作不能放在onCreate里面,如下载操作等耗时比较长的操作。我们把这些操作放在一些单独的线程里面。
Android 更新UI
错误的更新方式:
在非UI线程中更新UI
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); myText = (TextView)findViewById(R.id.text); new Thread(){ @Override public void run() { try { Thread.sleep(2000); myText.setText("hello android"); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }.start(); }
正确的使用方式,使用handler
Handler.post()方法直接执行了线程的run()方法,其实这个线程和Activity在同一个线程中。并没有调用start方法,没有启动新线程。
public class MainActivity extends Activity {
private TextView myText ;
private Handler handler = new Handler();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
myText = (TextView)findViewById(R.id.text);
new Thread(){
@Override
public void run() {
//这里使用post方法后这个线程是运行在UI线程中的
handler.post(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(2000);
myText.setText("hello android");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
}.start();
}
}
使用Callback对message进行拦截
需要引入包import android.os.Handler.Callback;//handler Callback 方法,可以对message进行拦截,如果返回true则拦截 private Handler handler2 = new Handler(new Callback() { //这个方法可以对接收到的message进行拦截 @Override public boolean handleMessage(Message msg) { Toast.makeText(getApplicationContext(), "1", Toast.LENGTH_SHORT).show(); return false; } }){ @Override public void handleMessage(Message msg) { Toast.makeText(getApplicationContext(), "2", Toast.LENGTH_SHORT).show(); } };
在UI线程创建Handler
UI线程默认会创建一个Looper,Handler在调用构造方法的时候会默认去关联这个Looper对象,所以在主线程中创建一个Handler的方法是Handler handler = new Handler(){ @Override public void handleMessage(Message msg) { // TODO Auto-generated method stub super.handleMessage(msg); } };
在子线程创建Handler
子线程中没有Looper对象,所以我们要自己去获取一个Loopoer对象,并且需要调用Looper.loop()方法,轮循处理消息。public class LooperThread extends Thread { @Override public void run() { // 将当前线程初始化为Looper线程
//当前线程里就产生了一个Looper对象,在创建Handler的时候会和其关联起来 Looper.prepare(); // ...其他处理,如实例化handler // 开始循环处理消息队列,这是一个死循环,有消息就处理,没有消息就阻塞 Looper.loop(); } }
Android 消息处理机制: Handler Message Looper
一 Handler封装了消息的发送,(主要包括消息发送给谁,一般发送给自己)Looper
1.内部包含一个消息队列也就是MessageQueue,所有的Handler发送的消息都走向消息队列。
2.Looper.Loop()方法,就是一个死循环,不断从MessageQueue取消息,如果有消息就处理,没有消息就阻塞。
二 MessageQueue ,就是一个消息队列,可以添加消息,并处理消息。
三 Handler也很简单,内部会跟Looper进行关联,也就是说在Handler的内部可以找到Looper,找到了Looper也就找到了MessageQueue,在Handler发送消息时其实是向MessageQueue队列中发送消息。
总结:handler负责发送消息,Looper负责接收Handler发送的消息,并把消息发送给handler自己,MessageQueue就是一个存储消息的容器。
Handler发送消息
有了handler之后,我们就可以使用
post(Runnable), postAtTime(Runnable, long), postDelayed(Runnable,long),sendEmptyMessage(int),sendMessage(Message), sendMessageAtTime(Message, long)和
sendMessageDelayed(Message, long)这些方法向MQ上发送消息了。光看这些API你可能会觉得handler能发两种消息,一种是Runnable对象,一种是message对象,这是直观的理解,但其实post发出的Runnable对象最后都被封装成message对象了。
1 message.target为该handler对象,这确保了looper执行到该message时能找到处理它的handler,即loop()方法中的关键代码。
Handler处理消息
// 处理消息,该方法由looper调用
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
// 如果message设置了callback,即runnable消息,处理callback!
handleCallback(msg);
} else {
// 如果handler本身设置了callback,则执行callback
if (mCallback != null) {
/* 这种方法允许让activity等来实现Handler.Callback接口,避免了自己编写handler重写handleMessage方法。
if (mCallback.handleMessage(msg)) {
return;
}
}
// 如果message没有callback,则调用handler的钩子方法handleMessage
handleMessage(msg);
}
}
// 处理runnable消息
private final void handleCallback(Message message) {
message.callback.run(); //直接调用run方法!
}
// 由子类实现的钩子方法
public void handleMessage(Message msg) {
}
HandlerThread的使用
注意:Handler属于哪个线程不是看它在哪里创建的,而是看其关联的Looper对象在哪个线程实现子线程向主线程互相发送消息,子线程中可以处理耗时任务
/* * 如何向子线程发送消息 */ public class FourthActivity extends Activity implements OnClickListener{ private Button sendButton; private Button stopButton; private HandlerThread thread; private Handler threadHandler; //创建一个和主线程相关的handler private Handler handler = new Handler(){ @Override public void handleMessage(android.os.Message msg) { //给子线程发送一个消息 Message message = new Message(); message.what =1;//这里需要设置和removeMessage方法中的参数一致,不然停止不了 threadHandler.sendMessageDelayed(message, 1000); Log.i("meng","main handler"); } }; @Override public void onCreate(android.os.Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.four); sendButton = (Button)findViewById(R.id.send_message); stopButton = (Button)findViewById(R.id.stop_message); sendButton.setOnClickListener(this); stopButton.setOnClickListener(this); thread = new HandlerThread("handler thread"); thread.start(); //创建一个子线程的handler threadHandler = new Handler(thread.getLooper()){ @Override public void handleMessage(android.os.Message msg) { Message message = new Message(); message.what = 1; //每隔1秒给主线程发送一个消息 handler.sendMessageDelayed(message, 1000); Log.i("meng","thread handler"); } }; } @Override public void onClick(View v) { // TODO Auto-generated method stub switch (v.getId()) { case R.id.send_message: //调用 handler.sendEmptyMessage(1); break; case R.id.stop_message: handler.removeMessages(1); break; default: break; } } }精彩博客链接: http://blog.csdn.net/lmj623565791/article/details/47079737/
http://blog.csdn.net/lmj623565791/article/details/38377229
http://blog.csdn.net/lmj623565791/article/details/38476887
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- Android IPC进程间通讯机制
- Android Manifest 用法
- [转载]Activity中ConfigChanges属性的用法
- Android之获取手机上的图片和视频缩略图thumbnails
- Android之使用Http协议实现文件上传功能
- Android学习笔记(二九):嵌入浏览器
- android string.xml文件中的整型和string型代替
- i-jetty环境搭配与编译
- android之定时器AlarmManager
- android wifi 无线调试
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- android 代码实现控件之间的间距
- android FragmentPagerAdapter的“标准”配置
- Android"解决"onTouch和onClick的冲突问题
- android:installLocation简析
- android searchView的关闭事件
- SourceProvider.getJniDirectories