Android Looper用法及分析

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

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

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

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

方法介绍

prepare()方法最终会传递true到 prepare(boolean quitAllowed)方法当中,这里直接看 prepare(boolean quitAllowed)方法。
在这里插入图片描述
这里可以看到该方法会优先判断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内容见下图:在这里插入图片描述

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

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

Looper(boolean quitAllowed)方法,实例化的时候会把传递过来参数作为实例化MessageQueue的参数,并且当前的线程会获取当前的线程,表述的可能不太清晰看图吧:
在这里插入图片描述

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()方法,这个就看图片吧。
在这里插入图片描述

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对外暴露的方法基本都已经写出。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android中的Looper类主要用于管理消息循环和消息队列。在Android中,每个线程都有一个Looper对象,它用于循环处理消息队列中的消息,以便在主线程或后台线程中处理异步任务。 使用Looper类,我们可以在Android应用程序中创建一个消息循环,并将消息动态地排队到消息队列中。然后,我们可以在消息队列中处理这些消息,以便在正确的时间和正确的上下文中执行相应的操作。 以下是使用Looper类的基本步骤: 1. 创建一个Handler对象并将其附加到当前线程的Looper。 2. 在需要发送消息的地方,使用Handler的post方法将消息发送到消息队列中。 3. 在Looper所在的线程中处理消息队列中的消息。 例如,下面的代码演示了如何在后台线程中使用Looper类: ``` public class MyThread extends Thread { public Handler mHandler; @Override public void run() { Looper.prepare(); mHandler = new Handler() { @Override public void handleMessage(Message msg) { // 在此处处理消息 } }; Looper.loop(); } } ``` 在这个例子中,我们创建了一个MyThread类,并在它的run方法中创建了一个消息循环和消息队列。然后,我们创建了一个Handler对象,并将其附加到当前线程的Looper中。最后,我们调用Looper的loop方法来开始处理消息队列中的消息。 使用这种方式,我们就可以在后台线程中动态地排队和处理消息,以便在正确的时间和正确的上下文中执行相应的操作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值