Looper的loop死循环为什么不会阻塞主线程

因为主线程的Looper实在ActivityThread里面准备出来,创建出来的,那么其实我们Android程序也就是Java程序,
你启动它,进入main方法,执行完所有的方法,也就会退出了,那么我们的应用程序你说总不能说执行完main方法就退出把?
所以肯定是要一个死循环要卡在那里,让我们的这个Android的应用不至于说执行那么一点代码就退出,所以这个在ActivityThread的mian方法里面回去首先准备一个主线的Looper方法,然后准备完了之后中间会有一些其他的内容,最后会有一个Looper.loop()会阻塞在哪里,而为什么我们写的代码不会因为这个looper而死循环呢?因为我们写的代码就是通过handler驱动起来的,我们activity的onCreate、onResume、onStop等等这些生命周期方法,包括我们的UI绘制的信号,这些UI绘制的事件都是通过Handler Looper循环内部发起的,来调用回调我们的各个Activity,各个Fragment等等这样的一些组件里面的各个生命周期方法,我们的代码就是在循环里面执行的,你说怎么会阻塞呢?而且你说死循环会不会导致我们的CPU一直在我们没消息的时候,它死循环会不会一直在那里空转,导致CPU一直帮你做事情,实际上你没有什么事情可做,那么其实这个Looper有一个死循环在使用之外,有一个nativePollOnce的这个方法,这个方法是个native方法,本地方法调用像对应的JNI接口,对应的C/C++方法,这里面其实是我们在Linux里面的一个管道机制,epoll,在没有消息的时候它会wait会进行一个等待,这时候调用完epoll_wait之后,没有消息的时候,它就会等待在那里,实际上调用完wait之后,就会释放我们的CPU,就等于我们的应用在休眠状态,它不会让CPU一直在哪里空转。

Thread的run方法如下:

@Override
public void run() {
    mTid = Process.myTid();
    Looper.prepare();
    synchronized (this) {
        mLooper = Looper.myLooper();
        notifyAll();
    }
    Process.setThreadPriority(mPriority);
    onLooperPrepared();
    Looper.loop();
    mTid = -1;
}
=


代码Looper.loop()是一个for死循环,然后突然想到主线程中也有Looper为什么不卡主线程于是找到了ActivityThread的源码

public static void main(String[] args) {

Looper.prepareMainLooper();

ActivityThread thread = new ActivityThread();

thread.attach(false);

if (sMainThreadHandler == null) {

sMainThreadHandler = thread.getHandler();

}

if (false) {

Looper.myLooper().setMessageLogging(new LogPrinter(Log.DEBUG, “ActivityThread”));

} // End of event ActivityThreadMain.

Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);

Looper.loop(); throw new RuntimeException(“Main thread loop unexpectedly exited”);

}

main方法的退出就是Looper.loop();的执行完毕,所有事件都是Looper的监听,主线程本事就是个阻塞。

Android是事件驱动,Looper内部是一个while死循华,只有程序退出后循环才会停止,如果Looper使用中死掉了,任何事件都不会有反应了。事件只会阻塞Looper,而Looper不会阻塞事件。
 

### Android主线程不被堵塞的原因与机制 Android主线程(也称UI线程)之所以不会因为`Looper.loop()`中的死循环阻塞,主要依赖于其事件驱动的设计和消息队列机制。以下是具体原因和机制的详细解析: #### 1. **事件驱动模型** Android应用基于事件驱动模型运行。主线程通过`Looper`不断从`MessageQueue`中提取并处理消息[^3]。每个点击、触摸事件以及生命周期回调(如`onCreate`、`onResume`等)都以消息的形式存入`MessageQueue`中[^5]。因此,即使`Looper.loop()`是一个死循环,它也不会阻塞主线程,因为它会持续监听并处理消息。 #### 2. **Looper与MessageQueue** - **Looper**:负责管理主线程的消息循环。`Looper.loop()`方法通过一个无限循环不断从`MessageQueue`中获取消息并分发给对应的`Handler`进行处理[^4]。 - **MessageQueue**:存储所有待处理的消息和任务。当没有消息时,`Looper`会调用`nativePollOnce`进入休眠状态,释放CPU资源[^3]。只有在有新消息到来时(如输入事件、Binder调用或定时器到期),线程才会被唤醒继续处理消息。 #### 3. **非阻塞的长任务处理** 如果在主线程中执行耗时操作(如网络请求或复杂计算),会导致`Looper`无法及时处理其他消息,从而引发ANR(Application Not Responding)。为了避免这种情况,Android推荐将耗时任务放在子线程中执行,并通过`Handler`或其他机制通知主线程更新UI。例如: ```java new Thread(() -> { // 耗时计算 int result = performLongComputation(); // 通知主线程更新UI Message msg = handler.obtainMessage(); msg.arg1 = result; handler.sendMessage(msg); }).start(); ``` #### 4. **UI线程的安全性** AndroidUI控件不是线程安全的,多线程并发访问可能导致不可预期的状态。为保证UI一致性,系统限制了只能在主线程中访问UI控件[^1]。虽然可以通过加锁机制实现线程安全,但这会显著降低性能,因此Android选择由开发者手动管理线程安全问题。 #### 5. **总结** 主线程不被堵塞的核心在于事件驱动模型和`Looper`与`MessageQueue`的协作机制。`Looper.loop()`虽然是一个死循环,但它会在无消息时进入休眠状态,仅在有事件触发时唤醒并处理消息[^3]。这种设计确保了主线程能够高效地响应用户交互和其他系统事件。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值