Android Handle机制浅析

来源:互联网 发布:数据统计量 编辑:程序博客网 时间:2024/05/19 11:48
Android为了安全方面的考虑,是不允许线程对UI线程进行直接操作的。
而如果我们想通过线程对界面进行操作,有如下的几种方法:
在子线程中提供了5中方法来实现与UI线程的交互:
第一种方法:Activity.runUiThread(Runnable)
第二种方法:View.post(Runnable);
第三种方法:View.postDelayed(Runnable);
第四种方法:Handler、Message、Looper

第五种方法:AsyncTask

这里说说Handler机制:

一.基本概念:

1. 消息类:Message类
 android.os.Message的主要功能是进行消息的封装,同时可以指定消息的操作形式
2. 消息通道:Looper
  在使用Handler处理Message时,需要Looper(通道)来完成。在一个Activity中,系统会自动帮用户启动Looper对象,而在一个用户自定义的类中,则需要用户手工调用Looper类中的方法,然后才可以正常启动Looper对象。Looper的字面意思是“循环者”,它被设计用来使一个普通线程变成Looper线程。所谓Looper线程就是循环工作的线程。
3. 消息操作类:Handler类
  Message对象封装了所有的消息,而这些消息的操作需要android.os.Handler类完成。handler起到了处理M消息的作用(只处理由自己发出的消息),它要执行一个任务(sendMessage),并在loop到自己的时候执行该任务(handleMessage),整个过程是异步的。


如图:

Handle的四大核心机制是:Message,Handle,Looper,target

是怎样的一个过程?

        1一个线程可以有多个hander,每个hander都有自己标识的target

2.一个线程只有一个looper(只负责从队列中按顺序循环取出消息)

然后每个handler把looper循环出的消息根据target标识来处理自己的消息。

二.常见问题:

问题1.Handle导致内存泄露及解决方案?

  由target和ThreadLocal解决。

  ThreadLocal是什么?

 JDK 1.2的版本中就提供java.lang.ThreadLocal,ThreadLocal为解决多线程程序的并发问题提供了一种新的思路。使用这个工具类可以很简洁地编写出优美的多线程程序,ThreadLocal并不是一个Thread,而是Thread的局部变量。具体请参照博客:http://lavasoft.blog.51cto.com/62575/51926/

  简单来说:它就是线程真正保存线程自己本地变量的容器。每一个线程都有自己的单独的一个空间,致使不同线程调用同个数据是不会发生混乱。 

问题2:handler为什么阻塞?

  1。在handler队列中,没有handler存在的情况,Looper就不发生阻塞,不会再从
消息队列中获取message
  2。如果handle创建的时间小于message队列中一些message的放入时间。
那么Looper就不会去轮询这些message了,产生阻塞。因为,Looper是先要看handle的脸色后再去轮询消息的。

问题3:内存泄露问题?


如图:如果开启线程向服务器加载图片,但加载不来。每个类里面都存有其他的对象的应用

,这个线程不会销毁,一直请求。这种强引用不会自动中断,就会内存溢出。
解决方案:中断引用
  Handler.removeMessage()
  Handler.romoveCallbacks

问题4:如果handler创建在子线程,如何更新接受到消息后更新ui?

 先看下面方法:
  Looper.myLooper()【当前Activity的线程,不可更新UI】
  Looper.prepare();
  Looper.loop();

new Thread(){//创建一个子线程public void run() {Looper.prepare();Handler hander=new Handler(Looper.myLooper()){public void dispatchMessage(android.os.Message msg) {//可以接受到消息,但不能在这个子线程中更新UI};};Looper.loop();};}.start();
如果找到主线程的Looper就可以了。
Looper.getMainLooper//ActivityThread创建的looper[可以更新UI]

new Thread(){//创建一个子线程public void run() {Handler hander=new Handler(Looper.getMainLooper()){public void dispatchMessage(android.os.Message msg) {//通过接受的消息,在子线程中更新UI};};};}.start();
原因:这个looper是主Activity初始化时,就创建的,既然是主线程当然可以更新UI。
looper对消息可以对我们自定义的message执行操作,而且还对系统定义消息类型,执行操作。

下篇博客讲下:第五种方法:AsyncTask





0 0