zoukankan      html  css  js  c++  java
  • 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。

  • 相关阅读:
    golang:bson.ObjectId与string转化
    Go语言的序列化与反序列化(gob)
    Go语言使用匿名结构体解析JSON数据
    Java课程设计---创建数据库工具类
    Java课程设计---实现登录(1)
    Java课程设计---新建项目及导入如何jar包
    Java课程设计---Eclipse基本环境配置
    Java课程设计---WindowBuilder插件安装
    Spring简单介绍
    【软件工程】简单考试题
  • 原文地址:https://www.cnblogs.com/xunzhi/p/5671410.html
Copyright © 2011-2022 走看看