Handler初步
Handler是什么?
- Handler是Android给我们提供用来更新UI的一套机制,也是一套消息处理的机制,我们可以发送消息,也可以通过它处理消息。
为什么要用Handler?
- Android在设计的时候,就封装了一套消息创建.传递.处理机制,如果不遵循这样的机制就没法更新UI信息的,就会抛出异常信息.
使用Handler遇到的问题?
- 子线程中存在实例化Handler时必须要使用Looper,否则会出错。
实现一个与线程相关的Handler
- 就是在线程Thread中声明Handler,其他地方都是主线程,所以不要在主线程中的handler中做耗时操作。
子线程和主线程互发消息
- 主线程给子线程发送:threadHandler.sendMessage();
- 子线程给主线程发送:mainHandler.sendmessage();
Andorid更新UI的几种方式
- runOnUiThread(Runnable)
- view.post(Runnable)
- handler sendMessage
- handler.post(Runnable)
非UI线程更新View
- 某些时候可以,但是不推荐使用;在onCreate()中使用子线程更新UI,但是不使用延时就可以了,因为检测当前线程是否是在onResume()中完成的。
Handler标准写法
- Handler的标准写法,避免的内存泄漏
- 内存泄漏:内部类会自动引用外部类,当Activity销毁时,handler如果正在运行,那么activity其实并没有真正的销毁,会造成内存泄漏 -- 在onDestroy()中将handler制为空
private final MyHandler handler = new MyHandler(this);
private static class MyHandler extends Handler {
/**
* 此处使用弱引用
* 强引用:new出来的对象,内存不够也不会销毁
* 软引用:内存不够才会销毁
* 弱引用:引用对象不存在就销毁
*/
private final WeakReference<Test1Activity> weakReference; --> 可以是View
public MyHandler(Test1Activity activity) {
weakReference = new WeakReference<Test1Activity>(activity);
}
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Test1Activity activity = weakReference.get();
if (activity != null) {
// 使用Activity对象访问外部对象
activity.textView.setText("你好呀!");
}
}
}~~~
# Handler怎么使用?
sendMessage、sendMessageDelayed
Messagemessage = handler.obtainMessage(what, arg1, arg2,obj);
// sendToTarget()方法与sendMessage()方法功能一样,Target就是handler,是封装好的一个方法
message.sendToTarget();
handler.sendMessage(message);~~~
3.post(Runnable) --> 调用在Runnable中更新UI
// 调用Runnable
handler.post(runnable);
Runnable runnable = new Runnable() {
@Override
public void run() {
index++;
index = index % 3;
image.setImageResource(img[index]);
handler.postDelayed(runnable, 500);
}
};~~~
postDelayed(Runnable,long) 在Runnable中更新 --> 通过handler.post等调用runnable
new Handler(new CallBack()) --> 可以截取handler发送的消息
handler.removeCallbacks(Runnable) --> 移除runnable,结束handler的操作
Handler handler = new Handler(new Callback() {
// Callback()是截取handler发送的消息,当返回值为false时,获得消息,原来的handleMessage()可以获得消息;
// 当返回值为true时,截取消息,原来的handleMessage()收不到消息
// 上面的handleMessage()是 new Callback()中的方法
// 下面的handleMessage()是 new Handler()中的方法
@Override
public boolean handleMessage(Message msg) {
Toast.makeText(Img2Activity.this, "1", Toast.LENGTH_SHORT).show();
return true;
}
}) {
public void handleMessage(Message msg) {
Toast.makeText(Img2Activity.this, "2", Toast.LENGTH_SHORT).show();
};
};~~~
Android为什么设计只能通过Handler机制更新UI呢?
- 最根本的目的就是解决多线程并发问题.
- 假设如果在一个Activity当中,有多个线程去更新UI,并且都没有加锁机制,会出现什么问题?--> 更新界面错乱
- 如果对更新UI的操作都进行加锁处理的话又会产生什么样的问题?--> 性能下降
- 总结:不用关心多线程的问题,所有的更新UI的操作,都在主线程的消息队列当中去轮询处理.
Handler原理
- Handler封装了消息的发送(主要包括消息发送给谁)
- Looper内部包含一个消息队列也就是MessageQueue,所有的Handler发送的消息都走向这个队列。Looper.Looper方法,就是一个死循环,不断的从MessageQueue取消息,如有消息就处理消息,没有消息就阻塞
- MessageQueue,就是一个消息队列,可以添加消息,并处理消息Handler内部会跟Looper进行关联,也就是说Handler的内部可以找到Looper,找到了Looper也就找到了MessageQueue,在Handler中发送消息,其实就是向 MessageQueue队列发送消息。MessageQueue是先进先出原则
- handler负责发送消息,Looper负责接受Handler发送的消息,并直接把消息回传给Handler自己,MessageQueue就是一个存储消息的容器
- 主线程创建时,同时也会创建MessageQueue和Looper对象
HandlerThread
- 系统定义的一个继承自Thread的类,我们可以在实例化Handler中指定handlerThread.getLooper()这样的Looper名字,这样我们的Handler就变成了子线程的handler,就可以做耗时操作了.
// 定义HandlerThread,是Thread的子类,就是一个线程
HandlerThread handlerThread = new HandlerThread("child_child");
// 启动线程
handlerThread.start();
// 此时的Handler就变成了子线程中的Handler,可以做一些耗时的操作
// 默认的情况下,Handler是主线程中的Handler,不可以做耗时操作
Handler handler = new Handler(handlerThread.getLooper()){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
// 在这里我们可以做一些耗时的操作
}
};~~~
网友评论