Handler机制原理

首先说说Handler 使用中隐藏的坑

1、delay的时间过长,导致 activity未被回收内存泄漏以及逻辑错误

  可以将Handler携程static静态内部类,或者而降handler中引用的activity位软引用

2、new 了过多的message,导致内存泄漏,应该在处理后remove这些msg

3、Activity finish()后应该remove所有的msg和runable

 

 

------------------------------------------------------------------------------------------------------------------------------

 

各种类的含义 

Message:消息,其中包含了消息ID,消息处理对象以及处理的数据等,由MessageQueue统一列队,终由Handler处理。

Handler:处理者,负责Message的发送及处理。使用Handler时,需要实现handleMessage(Message msg)方法来对特定的Message进行处理,例如更新UI等。

MessageQueue:消息队列,用来存放Handler发送过来的消息,并按照FIFO规则执行。当然,存放Message并非实际意义的保存,而是将Message以链表的方式串联起来的,等待Looper的抽取。

Looper:消息泵,不断地从MessageQueue中抽取Message执行。因此,一个MessageQueue需要一个Looper。

Thread:线程,负责调度整个消息循环,即消息循环的执行场所。

------------------------------------------------------------------------------------------------------------------------------

关系

Handler,Looper和MessageQueue就是简单的三角关系。

Looper和MessageQueue一一对应,创建一个Looper的同时,会创建一个MessageQueue。

而Handler与它们的关系,只是简单的聚集关系,即Handler里会引用当前线程里的特定Looper和MessageQueue。

这样说来,多个Handler都可以共享同一Looper和MessageQueue了。

这些Handler也就运行在同一个线程里,每个线程一个Loop而 一个MessageQueue。

 ------------------------------------------------------------------------------------------------------------------------------------------------------------

 使用:

子线程网主线程中发消息,直接在主线程中handler = new Handler(),子线程中可以直接用handler.sendmessage。。。

主线程网子线程中,Looper.prepare()... handler = new Handler()... looper.loop...然后handler.sendmessage

一个Message经由Handler的发送,MessageQueue的入队,Looper的抽取,又再一次地回到Handler的怀抱

 

 

Handler的处理过程运行在创建Handler的线程里

·      一个Looper对应一个MessageQueue

·      一个线程对应一个Looper

·      一个Looper可以对应多个Handler

·      不确定当前线程时,更新UI时尽量调用post方法

 

 

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Android的主线程循环创建

  Android程序的运行入口点可以认为是android.app.ActivityThread类的main()方法(源码2.3.3):

复制代码
    public static final void main(String[] args) {
        // other codes...

        // 创建主线程循环
        Looper.prepareMainLooper();
        if (sMainThreadHandler == null) {
            sMainThreadHandler = new Handler();
        }

        ActivityThread thread = new ActivityThread();
        thread.attach(false);

        // other codes...

        // 进入当前线程(此时是主线程)消息循环
        Looper.loop();

        // other codes...

        thread.detach();
        // other codes...
    }
复制代码

 

  这个main()方法里面为程序创建了主线程循环

  Looper类中的主线程创建方法prepareMainLooper()

 

 

-------------------------------------------------------------------------------------------------------------------------------------------------------------------------

 ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。

今天用子线程调Toast报了一个Can't create handler inside thread that has not calledLooper.prepare()错误。


解决办法很简单:
Looper.prepare();

new handler...

Looper.loop();




Looper
public static final void prepare() {
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
       sThreadLocal.set(new Looper());  //在当前线程中创建一个Looper
    }

private Looper() {
        mQueue = new MessageQueue();  //关键在这,创建Looper都干了什么。 其实是创建了消息队列
        mRun = true;
        mThread = Thread.currentThread();
    }


一般如果不是在主线程中又开启了新线程的话,一般都会碰到这个问题。
原因是在创建新线程的时候默认情况下不会去创建新的MessageQueue。

 

posted @ 2016-07-14 18:37  逊志  阅读(10349)  评论(0编辑  收藏  举报