简短回答:
nativePollOnce
方法用于“等待”,直到下一个 Message
可用。如果此调用期间花费的时间很长,您的主(UI)线程没有真正的工作要做,会等待下一个事件进行处理。不需要担心这个问题。
解释:
由于“主”线程负责绘制 UI 并处理各种事件,因此它的 Runnable
具有处理所有这些事件的循环。
该循环由 Looper
管理,其工作非常简单:处理 MessageQueue
中的所有消息。
例如,响应输入事件、帧渲染回调甚至您自己的Handler.post
调用,都可能向队列添加Message
。有时主线程没有工作要做(也就是说,队列中没有消息),这可能发生在完成渲染单个帧之后(线程刚刚绘制了一个帧并准备好下一个帧,只是等待适当的时间)。MessageQueue
类中的两个Java方法对我们很有趣:Message next()
和boolean enqueueMessage(Message, long)
。Message next()
顾名思义,从队列中获取并返回下一个消息。如果队列为空(没有任何内容可以返回),该方法会调用native void nativePollOnce(long, int)
,它将阻塞直到添加新消息。此时,您可能会问nativePollOnce
如何知道何时唤醒。那是一个非常好的问题。当向队列添加Message
时,框架调用enqueueMessage
方法,该方法不仅将消息插入队列,而且还会在需要唤醒队列时调用native static void nativeWake(long)
。nativePollOnce
和nativeWake
的核心魔法发生在本地(实际上是C ++)代码中。原生的MessageQueue利用了一个名为epoll
的Linux系统调用,它允许监视IO事件的文件描述符。 nativePollOnce
在某个文件描述符上调用epoll_wait
,而nativeWake
写入该描述符之一,这是IO操作之一,epoll_wait
等待。然后内核将等待状态的epoll线程取出,并继续处理新消息。如果您熟悉Java的Object.wait()
和Object.notify()
方法,则可以想象nativePollOnce
是Object.wait()
的粗略等效项,nativeWake
是Object.notify()
的粗略等效项,但它们的实现完全不同:nativePollOnce
使用epoll
,而Object.wait()
使用futex
Linux调用。值得注意的是,nativePollOnce
和Object.wait()
都不会浪费CPU周期,因为当线程进入任一方法时,它会因线程调度目的而被禁用(引用Object
类的javadoc)。但是,某些分析器可能错误地将epoll等待(甚至是Object等待)线程识别为正在运行并消耗CPU时间,这是不正确的。如果这些方法实际上浪费了CPU周期,则所有空闲应用程序都将使用100%的CPU,从而加热和减慢设备。
结论:
你不必担心nativePollOnce
。它只是表示所有消息的处理已经完成,线程等待下一个消息。这意味着你不应该给你的主线程过多的工作;)
nativePollOnce
如何知道等待多久或者何时唤醒? - Florian Walther