• linkedu视频
  • 平面设计
  • 电脑入门
  • 操作系统
  • 办公应用
  • 电脑硬件
  • 动画设计
  • 3D设计
  • 网页设计
  • CAD设计
  • 影音处理
  • 数据库
  • 程序设计
  • 认证考试
  • 信息管理
  • 信息安全
菜单
linkedu.com
  • 网页制作
  • 数据库
  • 程序设计
  • 操作系统
  • CMS教程
  • 游戏攻略
  • 脚本语言
  • 平面设计
  • 软件教程
  • 网络安全
  • 电脑知识
  • 服务器
  • 视频教程
  • JavaScript
  • ASP.NET
  • PHP
  • 正则表达式
  • AJAX
  • JSP
  • ASP
  • Flex
  • XML
  • 编程技巧
  • Android
  • swift
  • C#教程
  • vb
  • vb.net
  • C语言
  • Java
  • Delphi
  • 易语言
  • vc/mfc
  • 嵌入式开发
  • 游戏开发
  • ios
  • 编程问答
  • 汇编语言
  • 微信小程序
  • 数据结构
  • OpenGL
  • 架构设计
  • qt
  • 微信公众号
您的位置:首页 > 程序设计 >Android > Android HandlerThread 消息循环机制之源码解析

Android HandlerThread 消息循环机制之源码解析

作者:网友 字体:[增加 减小] 来源:互联网 时间:2017-05-26

网友通过本文主要向大家介绍了handlerthread,handlerthread用法,handlerthread详解,android handler,android handler用法等相关知识,希望对您有所帮助,也希望大家支持linkedu.com www.linkedu.com

Android HandlerThread 消息循环机制之源码解析


关于 HandlerThread 这个类,可能有些人眼睛一瞟,手指放在键盘上,然后就是一阵狂敲,马上就能敲出一段段华丽的代码:

HandlerThread handlerThread = new HandlerThread("handlerThread");
handlerThread.start();

Handler handler = new Handler(handlerThread.getLooper()){
    public void handleMessage(Message msg) {
        ...
    }
};
handler.sendMessage(***);

仔细一看,没问题啊(我也没说代码有问题啊),那请容许我说一句,“这代码敲也敲完了,原理懂不?”

为什么要扯这玩意,没什么理由,就是不小心看了这篇文章Android消息循环机制源码分析。学姐说了,源码都没看,没分析,还敢说你懂。原本还觉得自己懂了点,看完这句话,顿时就不确定了。于是,自觉打开了 AS …

前言

首先,先给各位看官打个预防针,待会要讲的东西可能有点多,有点绕,涉及的类包含有:HandlerThread、Thread、Handler、Looper、Message、MessageQueue,可能有些人已经遭不住啦,有种想要关闭网页的冲动。不要慌,刚开始我看源码的时候我也不知道最終会牵扯这么一大串出来,但仔细理一理后,其实就是那么回事。

一、擒贼先擒王 HandlerThread

这件事情的源头都是因它而起的,不先找它先找谁。

首先,HandlerThread 是什么gui,感觉像是 Handler 和 Thread 的结合体。点进源码一看:public class HandlerThread extends Thread {} 没什么好说的,原来是一个线程的子类。那么接下来就要看看这个 HandlerThread 到底有什么特殊之处。

HandlerThread handlerThread = new HandlerThread("handlerThread");
handlerThread.start();

跟正常线程的创建、启动步骤一样,线程已启动,那势必会执行其 run() 方法。为了方便下面流程的分析,这里先用代码块1表示:

#HandlerThread.java

public void run() {
    mTid = Process.myTid();
    Looper.prepare();
    synchronized (this) {
        mLooper = Looper.myLooper();
        notifyAll();
    }
    Process.setThreadPriority(mPriority);
    onLooperPrepared();
    Looper.loop();
    mTid = -1;
}

其中,Looper 就代表我们经常说的消息循环,Looper.prepare() 就代表消息循环执行前的一些准备工作。

二、抓捕各种小弟(Looper、MessageQueue、Message)

既然上面已经谈到Looper,那就来看一下它的几个方法:Looper.prepare() 和 Looper.loop()。
代码块2

#Looper.java

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));
}

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

static final ThreadLocal sThreadLocal = new ThreadLocal();
final MessageQueue mQueue;
final Thread mThread;

上面一路下来还是挺清晰的,总结一下:因为一个 Thread 只能对应有一个 Looper,所以只有满足条件下才会将 Looper 对象存放在类型为 ThreadLocal 的类属性里。当然在这之前还是要先 new 一个 Looper 对象,而在 Looper 的构造方法中又创建了两个对象 ,分别为mQueue(消息队列)和 mThread(当前线程)。整个 prepare 过程其实主要是创建了三个对象:Looper、MessageQueue、Thread。
好了,Looper.prepare() 这个过程已经分析完了。接着我们再看代码块1,里面有一段同步代码块,目的是为了获取 Looper 对象。方法跳转过去一看,原来就是将之前存进 ThreadLocal 里的Looper 对象取出 。

#Looper.java

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

接下来最关键的就是 Looper.loop() 这句代码,它也是 HandlerThread 这个类存在的价值所在。只要一执行这句代码,也就代表真正的消息循环开始啦:代码块3

#Looper.java

public static void loop() {
    final Looper me = myLooper();
    if (me == null) {
        throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
    }
    final MessageQueue queue = me.mQueue;

    // Make sure the identity of this thread is that of the local process,
    // and keep track of what that identity token actually is.
    Binder.clearCallingIdentity();
    final long ident = Binder.clearCallingIdentity();

    for (;;) {
        Message msg = queue.next(); // might block
        if (msg == null) {
            // No message indicates that the message queue is quitting.
            return;
        }

        // This must be in a local variable, in case a UI event sets the logger
        Printer logging = me.mLogging;
        if (logging != null) {
            logging.println(">>>>> Dispatching to " + msg.target + " " +
                    msg.callback + ": " + msg.what);
        }

        msg.target.dispatchMessage(msg);

        if (logging != null) {
            logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
        }

        // Make sure that during the course of dispatching the
        // identity of the thread wasn't corrupted.
        final long newIdent = Binder.clearCallingIdentity();
        if (ident != newIdent) {
            Log.wtf(TAG, "Thread identity changed from 0x"
                    + Long.toHexString(ident) + " to 0x"
                    + Long.toHexString(newIdent) + " while dispatching to "
                    + msg.target.getClass().getName() + " "
                    + msg.callback + " what=" + msg.what);
        }

        msg.recycleUnchecked();
    }
}

这个方法的作用就是开始从消息队列中循环取出消息。那这个消息队列又从哪来的呢,还记得我们在Looper.prepare() 中创建 Looper 对象的时候在其构造方法中 new 两个对象嘛,一个 MessageQueue,一个Thread。在这里要想使用消息队列,首先需要先获取 Looper 实例,毕竟消息队列 MessageQueue 是作为其成员属性而存在的;接着获得了消息队列的对象,并进入一个貌似死循环的控制流中。这个 for 语句干的事情就是不断的从消息队列 MessageQueue 里取出消息,然后发送出去。具体谁来处理这些消息马上揭晓。下面的代码就是从消息队列中取出消息:

#Looper.java

Message msg = queue.next()

接下去的内容可能就需要各位看官对数据结构有点了解了,我们一步一步嵌进去看一下。代码块4

#MessageQueue.java

Message next() {
    ...
    for (;;) {
        if (nextPollTimeoutMillis != 0) {
            Binder.flushPendingCommands();
        }

        nativePollOnce(ptr, nextPollTimeoutMillis);

        synchronized (this) {
            // Try to retrieve the next message.  Return if found.
            final long now = SystemClock.uptimeMillis();
            Message prevMsg = null;
            Message msg = mMessages;
            if (msg != null && msg.target == null) {
                // Stalled by a barrier.  Find the next asynchronous message in the queue.
                do {
                    prevMsg = msg;
                    msg = msg.next;
                } while (msg != null && !msg.isAsynchronous());
            }
            if (msg != null) {
                if (now < msg.when) {
                    // Next message is not ready.  Set a timeout to wake up when it is ready.
                    nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                } else {
                    // Got a message.
                    mBlocked = false;
                    if (prevMsg != null) {
                        prevMsg.next = msg.next;
                    } else {
                        mMessages = msg.next;
                    }
                    msg.next = null;
               



 
分享到:QQ空间新浪微博腾讯微博微信百度贴吧QQ好友复制网址打印

您可能想查找下面的文章:

  • Android HandlerThread 消息循环机制之源码解析
  • android源码解析之(三)--)HandlerThread
  • HandlerThread,handlerthread用法

相关文章

  • 2017-05-26Android中BroadcastReceiver组件详解
  • 2017-05-26android WebView控件显示网页,androidwebview
  • 2017-05-26自定义控件添加自定义属性问题,控件添加自定义属性
  • 2017-05-26Android刷机教程之LG Nexus 5X线刷官方Nexus系列教程,androidnexus
  • 2017-05-26Android面试题精选
  • 2017-05-26AppLaunchChecker
  • 2017-05-26android:Activity数据传递之静态变量
  • 2017-05-26Android 热修复原理及Gradle插件源码解析(以Nuwa为例)
  • 2017-05-26Android--BroadcastReceiver应用详解
  • 2017-05-26安卓界面高级组件------拖动条和评星条,安卓------拖动

文章分类

  • JavaScript
  • ASP.NET
  • PHP
  • 正则表达式
  • AJAX
  • JSP
  • ASP
  • Flex
  • XML
  • 编程技巧
  • Android
  • swift
  • C#教程
  • vb
  • vb.net
  • C语言
  • Java
  • Delphi
  • 易语言
  • vc/mfc
  • 嵌入式开发
  • 游戏开发
  • ios
  • 编程问答
  • 汇编语言
  • 微信小程序
  • 数据结构
  • OpenGL
  • 架构设计
  • qt
  • 微信公众号

最近更新的内容

    • Android-配置文件中设置“android:clickable=&quot;false&quot;无效的原因及解决办法,android-clickable
    • Android中Fragment与Activity之间的交互(两种实现方式),androidfragment
    • Android开发学习之路--传感器之初体验
    • android.view.InflateException: Binary XML file line #34: Error inflating class,
    • Android热补丁动态修复实践
    • andriod arcgis加载影像TIF,andriodarcgis
    • 解决关于 在android studio 出现的 DELETE_FAILED_INTERNAL_ERROR Error while Installing APK 问题,whileinstallingapk
    • android开发使用组件心得
    • android自定义控件(二),简易的数值输入器
    • Android MediaPlayer 音乐播放

关于我们 - 联系我们 - 免责声明 - 网站地图

©2020-2025 All Rights Reserved. linkedu.com 版权所有