zoukankan      html  css  js  c++  java
  • Handler消息源代码分析

        public static final Looper myLooper() {
            return (Looper)sThreadLocal.get();
        }

    首先到Handler运行过程的总结:


        1、 Looper.prepare()方法
            为当前线程绑定looper。
            在looper构造方法中创建一个messageQueue

        2、 创建handler 重并写handleMessage方法

        3、 使用handler发送消息,终于消息都会发送至messageQueue对象中。在messageQueue其中,全部的message按应该运行的时间的先后顺序,从小到大排列

        4、Looper.loop()
            在此方法中。开启死循环,不断的从messageQueue中取出应该运行的message,并运行message 相应的handler中的dispatchMessage方法。即。运行我们重写的handleMessage方法

    參照以上分析在子线程中创建Handler对象:

    	new Thread(){
    	    @Override
    	    public void run() {
    		Message msg = Message.obtain();
    		Looper.prepare();//若没有调用此方法则抛出异常 Can't create handler inside thread that has not called Looper.prepare()
    		Handler handler2 = new Handler(){
    		    public void handleMessage(Message msg) {
    			Toast.makeText(MainActivity.this, "收到子线程message消息", 0).show();
    		    };
    		};
    		handler2.sendMessage(msg);
    		Looper.loop();
    	    }
    	}.start();
    对照在主线程中创建Handler实例对象我们发现,在子线程中创建Handler对象须要在创建前调用Looper.prepare()方法在创建后调用Looper.loop方法,那到底这两个方法是做什么的呢?

    先看看系统的Looper.prepare方法:

    public static final void prepare() {
    
            if (sThreadLocal.get() != null) {
                throw new RuntimeException("Only one Looper may be created per thread");
            }
    		// 为当前线程绑定一个looper对象,以sThreadLocal为key
            sThreadLocal.set(new Looper());
        }
    即:调用Looper.prepare方法时为当前线程绑定了一个Looper对象,所以Looper.prepare方法仅仅能调用一次。即一个线程仅仅能有一个Looper对象

    再看看Looper的构造方法:

     private Looper() {
            mQueue = new MessageQueue();
        }
    由于一个线程仅仅能有一个Looper对象,所以一个线程也仅仅能有一个MessageQueue对象


    先让我们看看Handler的构造方法:

    public Handler() {
    	//获得当前线程的looper对象
            mLooper = Looper.myLooper();
            if (mLooper == null) {
                throw new RuntimeException(
                    "Can't create handler inside thread that has not called Looper.prepare()");
            }
    		// 获得looper中MessageQueue的引用
            mQueue = mLooper.mQueue;
        }

    再看看系统的Looper.myLooper方法:即获取调用Looper.prepare方法时保存在sThreadLoad的Looper对象,所以Looper.prepare方法要在new Handler方法前调用

        public static final Looper myLooper() {
            return (Looper)sThreadLocal.get();
        }

    即:当创建Handler时会先调用Looper.myLooper()方法获取当前线程的Looper对象,假设Looper==null,则抛出异常

    通过以上两个方法,当前线程的唯一Looper对象和MessageQueue对象都已创建,接下来该sendMessage了

    查看系统源代码可知:sendEmptyMessage等。发送信息的方法,终于都是调用了SendMessageAtTime(msg,when);

    而SendMessageAtTime(msg,when);方法终于的目的就是为了queue.enqueueMessage(msg, uptimeMillis);。当中msg为发送的Message对象,uptimeMillis为SystemClock.uptimeMillis() + when

    查看系统的enqueueMessage方法,该方法终于实如今messageQueue其中。全部的message按运行的先后顺序,从小到大排列

    final boolean enqueueMessage(Message msg, long when) {
           
                msg.when = when; // 将运行时间设置给msg.when
                Message p = mMessages;  // 定义变量p = mMessage  ,mMessage初终指向对列的第一个Message 对象
    
                if (p == null || when == 0 || when < p.when) {
    				// 当队列中为空的时候,mMessage = msg
                    msg.next = p;
                    mMessages = msg;
                    this.notify();
                } else {
    				// 否则将要进入队列的msg的运行时间和队列中的message的运行时间进行比較,
    				// 终于会使messageQueue中的全部的message按时间为顺序从小到大排列
    				// 即按运行的先后顺序排列
                    Message prev = null;
                    while (p != null && p.when <= when) {
                        prev = p;
                        p = p.next;
                    }
                    msg.next = prev.next;
                    prev.next = msg;
                    this.notify();
                }
            }

    消息发送成功这时候该调用Looper.loop方法:即完毕了从MessageQueue中取出须要运行的Message。并运行我们重写的handlMessage方法

     public static final void loop() {
    	//获得当前线程的looper对象及messageQueue对象
            Looper me = myLooper();
            MessageQueue queue = me.mQueue;
    
    	//开启while(true)循环
            while (true) {
    	    //从消息队列中取出一个message,假设message运行时间不到。那就wait等一会
                Message msg = queue.next(); // might block
    
    	    //运行message 相应的handler中的dispatchMessage方法。即。运行我们重写的handleMessage方法
                 msg.target.dispatchMessage(msg);
    
                }
            }
        }





















    版权声明:本文博主原创文章,博客,未经同意不得转载。

  • 相关阅读:
    Linux workqueue疑问【转】
    Java中基础类库使用
    Sdut 2164 Binomial Coeffcients (组合数学) (山东省ACM第二届省赛 D 题)
    python中使用mahotas包实现高斯模糊
    ZOJ1372 POJ 1287 Networking 网络设计 Kruskal算法
    Android 属性动画(Property Animation) 全然解析 (下)
    MySQL搜索: WHERE 多条件
    点滴记录——Centos 6.5 yum安装Ganglia
    标准linuxserver搭建
    检查ORACLE的警告文件的脚本
  • 原文地址:https://www.cnblogs.com/zfyouxi/p/4853793.html
Copyright © 2011-2022 走看看