Android Looper用法及分析

这篇具有很好参考价值的文章主要介绍了Android Looper用法及分析。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

先看一下源码中对looper进行的解释,
Android Looper用法及分析
根据注释内容,可以了解到,消息循环的交互情况都是通过handler进行的。
再不和handler搭配的情况下,通常都是以looper.prepare和looper.loop这种方式成对出现的,使在这两句话中间执行的内容都是通过looper进行通信执行相应内容。

此类还有对api实施进行注释描述,贴上来也一起看一下吧。
Android Looper用法及分析
这部分描述可以看到,looper基于MessageQueue并可以影响任务队列的状态。通常都是在MessageQueue或者Handler上进行定义,这里讲了looper的作用和其定义的时机。

个人理解:
looper通常都是在非主线程的时候使用让部分代码块可以作用在主线程,进行ui更新等一些操作。用到的地方有很多,在activityThread当中可以看到很多looper的影子。在什么时候用源码的注释上面解释的挺清晰了。
该类中中在跨进程部分运用的都是binder进行通信,threadlocal进行线程管理。

此类中不对外暴露的方法不进行介绍。
----------------------------------------------------------我是分割线----------------------------------------------------------

方法介绍

prepare()方法最终会传递true到 prepare(boolean quitAllowed)方法当中,这里直接看 prepare(boolean quitAllowed)方法。
Android Looper用法及分析
这里可以看到该方法会优先判断threadlocal线程池里面是否为null,里面有数据的时候就会抛出运行异常(因为代表这个时候looper有正在运行,必须要保持一个looper),里面没有数据的话就会把传递过来的boolean类型放到looper对象的参数中,然后设置到线程池里去运用。

getMainLooper方法,会锁住looper类,然后返回当前正在使用的looper。

myLooper()方法,会从当前的threadlocal获取内容并进行返回。

showSlowLog(long threshold, long measureStart, long measureEnd,String what, Message msg)方法,传递过来的参数如果还在倒计时,那么就打印log并返回为true,打印的log内容见下图:Android Looper用法及分析

myLooper()方法,会获取当前threadllocal里面的内容进行return。

myQueue()方法,执行mylooper方法获取其mQueue变量进行retun。

Looper(boolean quitAllowed)方法,实例化的时候会把传递过来参数作为实例化MessageQueue的参数,并且当前的线程会获取当前的线程,表述的可能不太清晰看图吧:
Android Looper用法及分析

isCurrentThread()方法,该方法会判断looper当前的sThread常量和Thread.currentThread()返回的变量是否相等(==)

setMessageLogging(@Nullable Printer printer)方法,会把传递过来的Printer 赋值给当前looper的mLogging变量。Printer 的用法还请再看相关介绍~

quit()方法,执行looper当前queue的quit(blooean)方法,传递false过去。

quitSafely()方法,同样执行queue的quit方法,但是会传递true过去,至于这个方法传递不同参数的含义请到queue分析当中去看。

getThread()方法,return looper当前的mThread。

getQueue()方法,return looper当前的mQueue。

dump(@NonNull Printer pw, @NonNull String prefix) 方法,会用传递过来的pw打印出prefix内容,然后执行mqueue.dump方法,该方法第三个参数为null。

dump(@NonNull Printer pw, @NonNull String prefix, Handler handler)方法,会用传递过来的pw打印出prefix内容,然后执行mqueue.dump方法,该方法第三个参数为传递过来的handler。具体执行内容也请看queue里面的dump方法。(该方法为hide,写多了)

toString()方法,这个就看图片吧。
Android Looper用法及分析

prepareMainLooper()方法,会把false传递到要执行的prepare方法中。然后synchronized-- looper类 判断当前的looper是否为null,为null的话就走myLooper方法进行获取,不为null则会抛出IllegalStateException。

loop方法内容比较多,也需要结合代码进行查看。先进行大概描述,然后再结合图片里面的代码进行查看。
looper.loop会先执行myLooper方法获取looper判断是否为null。获取当前looper的mQueue,进入到无限循环当中,获取queue里面的message。如果message为null就return,不为null时就会获取当前的observer,获取当前message里面的相关时间和tag用来判断message的执行时间。把相关tag放到trace.tracebegin当中进行跟踪。判断当前observer是否为空不为空的话执行相应方法,首先执行messageDispatchStarting方法,在message.target执行dispatchMessage之后执行observer.messageDispatched方法,如果这个时候走到catch里面了,会执行observer的dispatchingThrewException方法。trycatch最终都会跟踪该消息。判断时间打印出相应的log,最终会执行message.recycleUnchecked()重置message 的内容和Binder.clearCallingIdentity()方法清理标识。

public static void loop() {
        final Looper me = myLooper();
        if (me == null) {
            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
        }
        if (me.mInLoop) {
            Slog.w(TAG, "Loop again would have the queued messages be executed"
                    + " before this one completed.");
        }

        me.mInLoop = true;
        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();

        // Allow overriding a threshold with a system prop. e.g.
        // adb shell 'setprop log.looper.1000.main.slow 1 && stop && start'
        final int thresholdOverride =
                SystemProperties.getInt("log.looper."
                        + Process.myUid() + "."
                        + Thread.currentThread().getName()
                        + ".slow", 0);

        boolean slowDeliveryDetected = false;

        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
            final Printer logging = me.mLogging;
            if (logging != null) {
                logging.println(">>>>> Dispatching to " + msg.target + " " +
                        msg.callback + ": " + msg.what);
            }
            // Make sure the observer won't change while processing a transaction.
            final Observer observer = sObserver;

            final long traceTag = me.mTraceTag;
            long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs;
            long slowDeliveryThresholdMs = me.mSlowDeliveryThresholdMs;
            if (thresholdOverride > 0) {
                slowDispatchThresholdMs = thresholdOverride;
                slowDeliveryThresholdMs = thresholdOverride;
            }
            final boolean logSlowDelivery = (slowDeliveryThresholdMs > 0) && (msg.when > 0);
            final boolean logSlowDispatch = (slowDispatchThresholdMs > 0);

            final boolean needStartTime = logSlowDelivery || logSlowDispatch;
            final boolean needEndTime = logSlowDispatch;

            if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
                Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
            }

            final long dispatchStart = needStartTime ? SystemClock.uptimeMillis() : 0;
            final long dispatchEnd;
            Object token = null;
            if (observer != null) {
                token = observer.messageDispatchStarting();
            }
            long origWorkSource = ThreadLocalWorkSource.setUid(msg.workSourceUid);
            try {
                msg.target.dispatchMessage(msg);
                if (observer != null) {
                    observer.messageDispatched(token, msg);
                }
                dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
            } catch (Exception exception) {
                if (observer != null) {
                    observer.dispatchingThrewException(token, msg, exception);
                }
                throw exception;
            } finally {
                ThreadLocalWorkSource.restore(origWorkSource);
                if (traceTag != 0) {
                    Trace.traceEnd(traceTag);
                }
            }
            if (logSlowDelivery) {
                if (slowDeliveryDetected) {
                    if ((dispatchStart - msg.when) <= 10) {
                        Slog.w(TAG, "Drained");
                        slowDeliveryDetected = false;
                    }
                } else {
                    if (showSlowLog(slowDeliveryThresholdMs, msg.when, dispatchStart, "delivery",
                            msg)) {
                        // Once we write a slow delivery log, suppress until the queue drains.
                        slowDeliveryDetected = true;
                    }
                }
            }
            if (logSlowDispatch) {
                showSlowLog(slowDispatchThresholdMs, dispatchStart, dispatchEnd, "dispatch", 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对外暴露的方法基本都已经写出。文章来源地址https://www.toymoban.com/news/detail-514008.html

到了这里,关于Android Looper用法及分析的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Android handler用法及分析

    这里将handler机制中的message,looper和messagequeue分开分析,分开了解之后,会在进行一个总结。先来看handler里面都有哪些方法都做了哪些事情, hide方法和带有@UnsupportedAppUsage注释的方法(此方法不对外暴露使用)暂不描述 。 handler要传递的callback接口在handler类里面,该接口里面

    2024年02月05日
    浏览(42)
  • Android可换行的RadioGroup

            Android可换行的RadioGroup,有时候需要换行显示的单选列表,当然可以有多种实现方式,比如recycleview或者listview实现,本文采用的是RadioGroup+rediobutton方式实现。由于RadioGroup仅支持水平布局与垂直布局,故需要自定义控件实现。

    2024年02月02日
    浏览(44)
  • Ceph源码分析-在C++中,符号“&“和“*“有不同的用法。

    在C++中,符号\\\"\\\"和\\\"*\\\"有不同的用法。 \\\"\\\"符号: 在变量声明时,\\\"\\\"用于定义引用类型。例如: int a = 10; int ref = a;  这里的\\\"ref\\\"是一个引用,它引用了变量\\\"a\\\",对\\\"ref\\\"的修改会影响到\\\"a\\\"的值。 在函数参数中,\\\"\\\"用于传递参数的引用。例如: void foo(int num) { ... }  这里的\\\"num\\\"是一个引

    2024年02月01日
    浏览(41)
  • Android SharedPreferences源码分析

    SharedPreferences 是 Android 平台上轻量级的 K-V 存储框架。 SharedPreferences 采用 XML 文件格式持久化键值对数据,文件的存储位置位于应用沙盒的内部存储 /data/data/包名/shared_prefs/ 位置,每个 XML 文件对应于一个 SharedPreferences 对象。 一个sp文件(XML文件) 对应一个 SharedPreferences 对象

    2024年02月19日
    浏览(37)
  • Android Retrofit 源码分析

    Retrofit 是一个 RESTful 的 HTTP 网络请求框架的封装。 网络请求的工作本质上是 OkHttp 完成,而 Retrofit 仅负责 网络请求接口的封装。 1)App应用程序通过 Retrofit 请求网络,实际上是使用 Retrofit 接口层封装请求 参数、Header、Url 等信息,之后由 OkHttp 完成后续的请求操作。 2)在服

    2024年02月13日
    浏览(27)
  • Android OkHttp源码分析--分发器

    OkHttp是当下Android使用最频繁的网络请求框架,由Square公司开源。Google在Android4.4以后开始将源码中 的HttpURLConnection底层实现替换为OKHttp,同时现在流行的Retrofit框架底层同样是使用OKHttp的。 OKHttp优点: 1、支持Http1、Http2、Quic以及WebSocket; 2、连接池复用底层TCP(Socket),减少请求

    2024年02月13日
    浏览(37)
  • Android RIL&IMS源码分析

    1、了解IMS相关知识体系 2、RILD 与 RILJ、IMS回调消息的机制         IMS全称是IP Multimedia Subsystem,中文意义为IP多媒体子系统。IMS是一种基于IP基础结构,能够融合数据、话音和移动等网络技术的系统。          IP = 基于IP 的传输,基于IP的会话控制,基于IP的业务实现

    2024年02月09日
    浏览(38)
  • Android Bluetooth | 蓝牙配对源码分析

    好厚米们,我又来了! 这次分享的是 蓝牙设备执行配对动作时Android源码的执行流程。 下面先来说下, 应用层是如何发起蓝牙配对的: ( ps:大多数业务逻辑,都是扫描到可用设备后,点击可用设备 - 发起配对。) 这里我直接略过点击可用设备的步骤哈,扫描到第一个可用

    2024年02月06日
    浏览(48)
  • Android Compose 入门,深入底层源码分析

    我是跟着AS官网学习的,但是官方的教程写的不是很详细.官网链接 首先创建一个Compose项目,目录结构是这样: ui - theme - - Color.kt - - Theme.kt - - Type.kt MainActivity.kt 通过阅读源码,发现实际上还少了一个Shapes.kt,我手动添加了. 这个没什么好说的,官方的教程说的很明白了.这里简单贴一

    2024年04月10日
    浏览(48)
  • Android JetPack深入分析Lifecycle源码

    关键类介绍 Lifecycle 定义: 用于存储有关组件(如 activity 或 fragment)的生命周期状态的信息,并允许其他对象观察此状态。 它是一个 抽象类 ,具体实现类为 LifecycleRegistry ; 内部提供了 addObserver(LifecycleObserver observer) 添加观察者 、 removeObserver(LifecycleObserver observer)移除观察者

    2024年02月12日
    浏览(84)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包