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

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.

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值