Android笔记(三十三) Android中线程之间的通信(五)Handle、Looper和MessageQueue

ThreadLocal

往下看之前,需要了解一下Java的ThreadLocal类,可参考博文:

解密ThreadLocal

Looper、Handler和MessageQueue

我们分析一下之前的这段代码,查看一下Handler机制中,Handle、Looper和MessageQueue之间到底是什么关系

class WorkerThread extends Thread {
        @Override
        public void run() {
            super.run();
            Looper.prepare();
            handler = new Handler() {
                @Override
                public void handleMessage(Message msg) {
                    super.handleMessage(msg);
                    Log.d("TTTT", "handleMessage:" + Thread.currentThread().getName());
                    int i = msg.what;
                    Log.d("TTTT", "收到了消息对象:" + i);
                }
            };
            Looper.loop();
        }
    }

1. 首先执行 Looper.prepare() ;

查看Looper的源代码,路径为:sources\android-19\android\os\Looper.java

首先,Looper类的几个成员变量

    // sThreadLocal.get() will return null unless you‘ve called prepare().
    static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
    private static Looper sMainLooper;  // guarded by Looper.class
    final MessageQueue mQueue;
    final Thread mThread;

这就表明,每一个Looper对象,都与一个消息队列(MessageQueue)相对应,同时也与一个线程(Thread)相对应。

当我们调用Looper的prepare()方法的时候,执行如下代码:

public static void prepare() {
    prepare(true);
}
private static void prepare(boolean quitAllowed) {
    if (sThreadLocal.get() != null) {
        throw new RuntimeException("Only one Looper may be created per thread");
    }
    sThreadLocal.set(new Looper(quitAllowed));
}

从上面的代码可以看出,当执行了Looper.prepare()之后,会先调用ThreadLocal的get方法,判断是否已经存在以当前线程为键的键值对,如果已经存在,则抛出异常 “Only one Looper may be created per thread” 。如果不存在,则执行 sThreadLocal.set(new Looper(quitAllowed)) ;新建一个Looper对象,存入ThreadLocal中。

private Looper(boolean quitAllowed) {
    mQueue = new MessageQueue(quitAllowed);
    mThread = Thread.currentThread();
}

可以看出,创建Looper对象的同时,新建了一个MessageQueue对象,赋值给Looper对象的mQueue属性,将当前线程,赋值给Looper的mThread属性。

2. 接下来执行

    handler = new Handler() {
                @Override
                public void handleMessage(Message msg) {
                    super.handleMessage(msg);
                    Log.d("TTTT", "handleMessage:" + Thread.currentThread().getName());
                    int i = msg.what;
                    Log.d("TTTT", "收到了消息对象:" + i);
                }
            };

实例化一个Handler对象,执行其handleMessage方法,查看Handler的源码,路径:sources\android-19\android\os\Hnadler.java

可以看到Handler类有如下成员变量

    final MessageQueue mQueue;
    final Looper mLooper;
    final Callback mCallback;
    final boolean mAsynchronous;
    IMessenger mMessenger;

找到其Handler的构造方法

    public Handler() {
        this(null, false);
    }
        public Handler(Callback callback, boolean async) {
        if (FIND_POTENTIAL_LEAKS) {
            final Class<? extends Handler> klass = getClass();
            if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
                    (klass.getModifiers() & Modifier.STATIC) == 0) {
                Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
                    klass.getCanonicalName());
            }
        }

        mLooper = Looper.myLooper();
        if (mLooper == null) {
            throw new RuntimeException(
                "Can‘t create handler inside thread that has not called Looper.prepare()");
        }
        mQueue = mLooper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }

调用了Looper的 myLooper() 方法赋值给mLooper

    mLooper = Looper.myLooper();

我们查看Looper.java

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

发现将当前线程为键的Looper对象从ThreadLocal中取出并返回,所以,在创建Handler对象的时候,Handler对象的拿到了之前创建的Looper对象

  if (mLooper == null) {
    throw new RuntimeException(
                "Can‘t create handler inside thread that has not called Looper.prepare()");
  }

如果拿到的Looper对象为空,则抛出异常 “Can‘t create handler inside thread that has not called Looper.prepare()” 告知用户在没有调用Looper.preapre()之前,不能创建Handler对象。

    mQueue = mLooper.mQueue;
    mCallback = callback;
    mAsynchronous = async;

然后将Looper对象的mQueue给Handler的mQueue。

这样,就将Thread、Handler、Looper、MessageQueue联系起来了。

  

时间: 2024-10-13 21:57:47

Android笔记(三十三) Android中线程之间的通信(五)Handle、Looper和MessageQueue的相关文章

Android笔记(三十三) Android中线程之间的通信(五)Thread、Handle、Looper和MessageQueue

ThreadLocal 往下看之前,需要了解一下Java的ThreadLocal类,可参考博文: 解密ThreadLocal Looper.Handler和MessageQueue 我们分析一下之前的这段代码,查看一下Handler机制中,Handle.Looper和MessageQueue之间到底是什么关系 package cn.lixyz.handlertest; import android.app.Activity; import android.os.Bundle; import an

Android笔记(三十四) Android中线程之间的通信(六)Handle中的post()方法详解

我们之前都是使用sendMessage()方法来发送消息,使用handleMessage来处理消息的,今天我们来看另外一种方法,先看代码: package cn.lixyz.handlertest; import android.app.Activity; import android.os.Bundle; import android.os.Handler; import android.util.Log; import android.view.View; import android.wi

Android笔记(三十二) Android中线程之间的通信(四)主线程给子线程发送消息

之前的例子都是我们在子线程(WorkerThread)当中处理并发送消息,然后在主线程(UI线程)中获取消息并修改UI,那么可以不可以在由主线程发送消息,子线程接收呢?我们按照之前的思路写一下代码: package cn.lixyz.handlertest; import android.app.Activity; import android.os.Bundle; import android.os.Handler; import android.os.Message; import andr

Android笔记三十三.BroadcastReceiver使用

广播是一种广泛运用在应用程序之间传输信息的机制,而BroadcastReceiver是对发送出来的广播进行过滤接收并响应的一类组件. BroadcastReceiver本质上是一种全局监听器.用于监听系统全局的广播消息并接收指定的广播,因此它能够很方便地实现系统中不同组件之间的通信.例如以下为BroadcastReceiver知识点结构: 一.发送与接收广播 1.发送广播   广播的发送通过调用Context.sendBroadcast().Context.sendOderedBroadcast

Android笔记(六十三) android中的动画——逐帧动画( frame-by-frame animation)

就好像演电影一样,播放实现准备好的图片,来实现动画效果. 逐帧动画需要用到AnimationDrawable类,该类主要用于创建一个逐帧动画,然后我们把这个动画设置为view的背景即可. android提供两种方法为AnimationDrawable添加帧:XML定义和JAVA代码创建. XML 因为动画帧的资源需要是一个Drawable对象,所以需要把它放到Drawable目录下.在<animation-list>使用<item>来添加一帧 anima.xml <?xml

Android笔记二十三.Android基于事件监听器处理机制

转载请表明出处:http://blog.csdn.net/u012637501(嵌入式_小J的天空) 一.Android的事件处理 Android事件处理包括两个部分:Android事件处理机制(基本)和Android消息传递机制(进阶).前者包含三种处理方式,即基于监听的事件处理.基于回调的事件处理.直接绑定到标签;后者包含两种处理方式,即Handler消息传递.异步任务处理. 1.Android的事件处理机制 (1)基于监听的事件处理方式 通常做法是为Android界面组件绑定特定的事件监听

Android笔记(七十三) Android权限问题整理 非常全面

Android权限系统非常庞大,我们在Android系统中做任何操作都需要首先获取Android系统权限,本文记录了所有的Android权限问题,整理一下分享给大家. 访问登记属性 android.permission.ACCESS_CHECKIN_PROPERTIES读取或写入登记check-in数据库属性表的权限 获取错略位置 android.permission.ACCESS_COARSE_LOCATION通过WiFi或移动基站的方式获取用户错略的经纬度信息,定位精度大概误差在30~150

Java多线程中线程间的通信

一.使用while方式来实现线程之间的通信 package com.ietree.multithread.sync; import java.util.ArrayList; import java.util.List; public class MyList { private volatile static List list = new ArrayList(); public void add() { list.add("apple"); } public int size() {

java线程之间的通信

1.常用的方法 sleep()该线程进入等待状态,不释放锁 wait() 该线程进入等待状态,释放锁 notify() 随机唤醒一个线程 notifyAll() 唤醒全部线程 2.线程之间的通信 a.两个线程之间的通信 public class ThreadExchange { @Test public void test2Thread() { MyPrint myPrint = new MyPrint(); new Thread(new Runnable() { @Override publi