美文网首页工作生活
主线程中的Looper.loop()一直无限循环为什么不会造成A

主线程中的Looper.loop()一直无限循环为什么不会造成A

作者: 晓涵说 | 来源:发表于2019-07-02 07:09 被阅读0次

    1.引言
    众所周知在Activity的主线程中不能做耗时操作,但是 查看ActivityThread的源码可以看到,该线程中包含了一个Loop.looper()的阻塞操作,那么该阻塞操作为何不会引起ANR?
    2.源码分析
    其实引起ANR的原因主要包括以下两点:

    1.当前的事件没有机会得到处理(即主线程正在处理当前事件,没有及时完成或looper中的事件分发处理被阻塞);
    2.当前事件正在执行,但没有及时完成。

    为了避免ANR的产生,安卓中引入了Handler的处理机制,通过查看ActivtyThread的源码可以看出:

        public static final void main(String[] args) {
            ...
            //创建Looper和MessageQueue
            Looper.prepareMainLooper();
            ...
            //开始轮询
            Looper.loop();
            ...
        }
    

    查看Looper.loop()方法,该方法的操作与我们熟悉的Handelr处理机制类似,分为两步操作:取出消息和分发消息。

       while (true) {
           //取出消息队列中的消息
           Message msg = queue.next(); // might block
           ...
           /根据Message中的target标签,交给对应的Handle处理
           msg.target.dispatchMessage(msg);
           ...
        }
    

    因此在ActivityThread的main方法中主要是做消息的循环操作,一旦退出该循环操作,那么当前应用就退出了。
    但是该死循环是在主线程中操作,为何不会引起ANR呢?
    通过查看ActivityThread的handleMessage的源码可以看出,Android是由事件驱动的,常见的触摸和Activity的生命周期都是运行在Looper.loop()的控制之下,如果该循环停止了,那么整个应用也停止了。

     public void handleMessage(Message msg) {
            if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
            switch (msg.what) {
                case LAUNCH_ACTIVITY: {
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
                    final ActivityClientRecord r = (ActivityClientRecord) msg.obj;
                    r.packageInfo = getPackageInfoNoCheck(r.activityInfo.applicationInfo, r.compatInfo);
                    handleLaunchActivity(r, null);
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                }
                break;
                case RELAUNCH_ACTIVITY: {
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityRestart");
                    ActivityClientRecord r = (ActivityClientRecord) msg.obj;
                    handleRelaunchActivity(r);
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                }
                break;
                case PAUSE_ACTIVITY:
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityPause");
                    handlePauseActivity((IBinder) msg.obj, false, (msg.arg1 & 1) != 0, msg.arg2, (msg.arg1 & 2) != 0);
                    maybeSnapshot();
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    break;
                case PAUSE_ACTIVITY_FINISHING:
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityPause");
                    handlePauseActivity((IBinder) msg.obj, true, (msg.arg1 & 1) != 0, msg.arg2, (msg.arg1 & 1) != 0);
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    break;
                ...........
            }
        }
    

    通过查看上面的源码可以看出Activity的整个生命周期都是依靠Looper.loop(),在不同的生命周期执行时发送不同的消息,handleMessage接收到不同的Message后,根据case判断进行相应的处理。

    由于Activty的执行是遵循一定的生命周期方法的,因此如果某个周期的方法做过多的耗时操作,必然会影响下个周期的执行时间,整个生命周期的执行就会出现卡顿,继而会产生ANR的出现。

    并且主线的Looper对于消息的处理时,当子线程有消息发送时才会被唤醒,但子线程没有消息发送时,处于待唤醒状态,因此不会对CPU的性能产生影响。
    3.总结
    因此:主线程的Looper.loop()中死循环本身不会对Activity产生ANR,除非其消息事件本身的处理存在耗时操作,才会产生ANR.

    欢迎关注晓涵说(CSDN)xukang868(github)账号信息,查看更多文章。

    相关文章

      网友评论

        本文标题:主线程中的Looper.loop()一直无限循环为什么不会造成A

        本文链接:https://www.haomeiwen.com/subject/ocjacctx.html