安卓handler源码(androidstudio源码)

Android多线程还有HandleThread,看名字就可以能感觉到得到,会是handler和Thread的综合使用。那到底什么怎么样的呢,就跟随Android的源码来看看他的工作原理是什么样的。我们先看看他的类注解:先看看官方对他的介绍:【Handyclassforstartinganewthreadthathasalooper.Theloopercanth…

大家好,又见面了,我是你们的朋友全栈君。

前言

Android 多线程还有HandleThread,看名字就可以能感觉到得到,会是handler和Thread的综合使用。那到底是怎么样的呢,现在就跟随Android的源码来看看他的工作原理是什么样的。

我们先看看他的类注解:先看看官方对他的介绍:【 Handy class for starting a new thread that has a looper. The looper can then be  used to create handler classes. Note that start() must still be called.】简单的翻译就是这是一个很方便启动一个拥有looper的的类,这个Looper在这以后是用来创建handler类的,注意:thread的start()方法一定要被调用。

理解HandleThread

看到介绍可能觉得HandleThread有点厉害,有looper还能创建handler。我们抱着这样的心情去看HandleThread比较难受,所以,我们要换一下思路,这个HandleThread就是个Thread,这个Thread执行工作任务,我们通过handler给这个Thread安排工作。【从使用角度就相当于我们自己起一个工作线程,然后在线程中自己prepareLooper一样。只不过HandleThread已经把这些做好了,还封装了优先级设置,安全退出等一些辅助功能,让我们开发人员使用起来更加方便

handler我们知道可以用来线程间通信,之前在Handler工作流程梳理里面分析过【具体在本篇就不细说】,我们这里要知道,Handler可以把Message发送到MessageQueue中,通过Looper.loop()循环将Message取出并分派到到相应的Handler去处理。同一个线程中只有一个MessageQueue和Looper, Message的处理是串行的。当有Thread使用了Handler,那么通过Handler给Thread安排任务也是串行执行的,就是一个执行完才执行下一个,所以这个HandleThread不适多耗时任务,这样任务的执行相互收影响比较严重。对于任务量小,使用频繁的任务来说就比较友好,可以使用一个线程来实现线程池的效果,节省了资源。

源码分析

看了上面的理解描述后,我们就可以猜到HandleThread代码逻辑应该不复杂,代码量也不会很大。事实就是这样,加上注解,HandleThread的代码在160多行。

/frameworks/base/core/java/android/os/HandlerThread.java

public class HandlerThread extends Thread {
    int mPriority;
    int mTid = -1;
    Looper mLooper;
    private @Nullable Handler mHandler;

    public HandlerThread(String name) {
        super(name);
        mPriority = Process.THREAD_PRIORITY_DEFAULT;
    }

    /**
     * Constructs a HandlerThread.
     * @param name
     * @param priority The priority to run the thread at. The value supplied must be from
     * {@link android.os.Process} and not from java.lang.Thread.
     */
    public HandlerThread(String name, int priority) {
        super(name);
        mPriority = priority;
    }
    ...
}

HandleThread继承自Thread,首先我们就看到了该有的Looper对象,然后从它的构造函数看,可以设置线程优先级和给线程命名。在使用时如果不设置优先级,会默认设置为Process.THREAD_PRIORITY_DEFAULT;

HandleThread主要的逻辑就在run()方法里面

1.run()

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

在run()里。Looper.prepare()来初始化当前线程的一个Looper。然后拿到一个looper对象 赋值给mLooper,呃呃呃。这里为啥要notifyAll(),在Java中wait()和notify/notifyAll是一起使用的,主要用在多线程中,,用在这里又是为什么?我们在HandleThread搜索一下wait()果然有:

1.2 getLooper()

public Looper getLooper() {
    ...
    // If the thread has been started, wait until the looper has been created.
    synchronized (this) {
        while (isAlive() && mLooper == null) {
            try {
                wait();
            } catch (InterruptedException e) {
            }
        }
    }
    return mLooper;
}

在getLooper()方法里,当looper还没有创建时间,需要当前线程保持wait,这是为什么呢?我估计是当线程启动,在没有获取到looper之前,当前线程是空闲的,也没任务做,就先释放资源,让其他线程先执行run()方法来获取Looper对象,然后将looper赋值给mLooper,【当我看到这里时是很疑惑的,这个在文章后面来介绍】;

再回到run()方法中;获mLooper赋值后,随后调用notifyAll(),【此时其他线程的getLooper()方法也会被唤醒,就可以利用looper去创建handler。然后再handleMessage()中实现处理任务的业务代码】;然后接下里就主要是进入loop循环了。这就之前分析handler看到的线程最后的状态是一毛一样,那就是随后线程都会进入到loop循环中。

以上就是HandleThread的主要原理了。

———————————————————-华丽丽的分割线————————————————————————–

疑惑

现在要来说说我在分析那个mlooper被赋值时遇到的疑惑,还记得我们在Handler工作流程梳理事看到Looper.getLooper()最后是从ThreadLoacl中取出的,在Android_ThreadLoacl原理一篇中,我们知道threadLocal保存的变量是与线程相关联的,所以不同线程get到的Looper是不一样的。

疑点来了啊,注意听。假如线程A运行到HandleThread的getLooper()方法,如果此时mlooper为空。那么线程A就会wait,阻塞在这里;那么后来线程B运行到HandleThread的run()方法,从线程B中获取到线程B的looper,然后赋值给mLooper;之后线程A就可以被唤醒,返回mLooper;那么这时候线程A返回的looper其实是在线程B中创建的looper,我就很乱了,,,不应该looper和线程相关的吗?在这里怎么可以这么玩?

反正我是很乱的,问了同事也还没问个明白。有一点肯定的,源码中这么玩肯定是没错的,我需要一个可以让自己信服的理由。

既然没问道直接的答案,按我自己试试,然后,我写了个demo,在主线程中获取主线程的MainLooper,然后在子线程创建Handler时直接传入MainLooper。最后发现, 子线程是可以使用主线程的looper。恩恩,终于,用事实说明了,多线是可以公用looper的。好了,HandleThread中的疑惑解决了;

接下来,我就有了新疑惑,我需要继续搞明白,为什么多线程可以共用looper。这和我之前的理解不一样,我之前的理解是线程中的looper和线程相关,当前线程只能使用当前线程的Looper。

解惑

答案还是得要在源码里面找,经过观察发现HandleThread和我们一般的在子线程中创建Handler的方式是不同的;

  • 子线程中直接我们一般是这样的:
/ * 
  * <pre>
  *  class LooperThread extends Thread {
  *      public Handler mHandler;
  *
  *      public void run() {
  *          Looper.prepare();
  *
  *          mHandler = new Handler() {
  *              public void handleMessage(Message msg) {
  *                  // process incoming messages here
  *              }
  *          };
  *
  *          Looper.loop();
  *      }
  *  }</pre>
  * /
  • 使用HandelrThread时是这样的
private HandlerThread mMyhandleThread = new HandlerThread("MyHandleThread");
Handler mHandler;
mMyhandleThread.start();
mHandler = new Handler(mMyhandleThread.getLooper()) {
            @Override
            public void handleMessage(Message msg) {
            // TODO
            }
};

我感觉问题还是在Handler上。那我们就去看看Handler 的构造函数:

/frameworks/base/core/java/android/os/Handler.java

// 1.我们一般手动在子线程就是这样创建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 " + Thread.currentThread()
                    + " that has not called Looper.prepare()");
    }
    mQueue = mLooper.mQueue;
    mCallback = callback;
    mAsynchronous = async;
}
//------------------------华丽丽的分割线------------------------

// 2.我们一般使用HandlerThread时是这样创建Handler的
public Handler(Looper looper) {
    this(looper, null, false);
}
...
public Handler(Looper looper, Callback callback, boolean async) {
    mLooper = looper;
    mQueue = looper.mQueue;
    mCallback = callback;
    mAsynchronous = async;
}

通过对不同方式创建Handler时调用的构造方法,我们发现 ,handler的如果在构造函数中指定了Looper,就直接使用传进来的looper对象,如果在构造事没有传入looper对象,则此时就需要使用本线程自己的looper;至于messageQueue只是和Looper相关,MessageQueue和handler并没有直接联系。

结论

所以我们得出结论,多线程可以使用同一个Looper,相应的也就是使用了相同的MessageQueue。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/126973.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • Android学习路线(二十)运用Fragment构建动态UI[通俗易懂]

    Android学习路线(二十)运用Fragment构建动态UI

  • pip安装的包pycharm识别不了_手机上的python安装第三方库

    pip安装的包pycharm识别不了_手机上的python安装第三方库问题描述:在cmd控制台pipinstallpytest后并显示安装成功后,并且尝试用pycharm的python中importpytest,显示异常,提示我未安装过pytest解决方法方法一:在PyCharm下载第三方库(即把之前下的库作废,这里重新再下一次……)方法二:坚持用pip的方法安装第三方库方法1:无需命令,通过pycharm操作即可,找到“pytest”点击“install”安装即可(由于我已经安装)方法2:我们…

  • Jenkins使用教程

    Jenkins使用教程Jenkins是一款流行的开源持续集成(ContinuousIntegration)工具,广泛用于项目开发,具有自动化构建、测试和部署等功能。本文以CentOS7环境为例,总结了Jenkins的安装与配置、邮件功能使用,并接入阿里巴巴的著名开源项目fastjson,以此演示Java项目(SVN+Maven)中FindBugs/CheckStyle/PMD等常用插件的使用、单元…

  • java 函数式编程(java自定义函数)

    以前写过一篇java8的流操作,人们都说流操作是函数式编程,但函数式编程是什么呢?什么是函数式编程什么是函数式编程?它是一种编程范式,即一切都是数学函数。函数式编程语言里也可以有对象,但通常这些对象都是恒定不变的——要么是函数参数,要什么是函数返回值。函数式编程语言里没有for/next循环,因为这些逻辑意味着有状态的改变。相替代的是,这种循环逻辑在函数式编程语言里是通过递归、把函…

  • 数论的概念_数论难吗

    数论的概念_数论难吗转载自:https://blog.csdn.net/whereisherofrom/article/details/78922798素数:http://www.cnblogs.com/fzl194/

  • ARM版Oracle安装包_如何把Linux移植到手机

    ARM版Oracle安装包_如何把Linux移植到手机  linux作为一款流行的嵌入式系统,目前已经有多种架构的MCU支持Linux移植,arm64就是其中一种。今天在这里想做一个笔记,记录一下完整的arm64移植过程。嵌入式Linux系统组成部分嵌入式Linux移植到开发板上时,主要有四个组成部分,下面一一列举。  在启动过程中,bootloader加载设备树文件(dtb),之后启动内核(Startkernel),进而加载根文件系统(debian或者ubuntu),最后进入系统。  那么我们所做的工作可以分为以下三部分:1、进行bootlo

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号