AndroidLooper用法及分析-创新互联

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

成都创新互联长期为1000+客户提供的网站建设服务,团队从业经验10年,关注不同地域、不同群体,并针对不同对象提供差异化的产品和服务;打造开放共赢平台,与合作伙伴共同营造健康的互联网生态环境。为孝昌企业提供专业的做网站、网站建设孝昌网站改版等技术服务。拥有十余年丰富建站经验和众多成功案例,为您定制开发。

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

你是否还在寻找稳定的海外服务器提供商?创新互联www.cdcxhl.cn海外机房具备T级流量清洗系统配攻击溯源,准确流量调度确保服务器高可用性,企业级服务器适合批量采购,新人活动首月15元起,快前往官网查看详情吧


本文题目:AndroidLooper用法及分析-创新互联
转载来于:http://myzitong.com/article/dcdoig.html