AsyncTask陷阱:Handler,Looper与MessageQueue剖析

1 下载量 192 浏览量 更新于2024-08-29 收藏 235KB PDF 举报
AsyncTask是Android中用于执行后台任务的一个基础工具,它在主线程中创建并启动,但执行任务时可以在指定线程(默认为子线程)中运行,从而避免阻塞用户界面。然而,在某些特定情况下,如给定的示例中,AsyncTask可能会陷入一些隐藏的陷阱,这主要是由于不当使用了Handler、Looper和MessageQueue的关系。 首先,让我们理解关键概念: 1. **Handler**: Handler是Android中的一个重要组件,它负责将消息发送到线程的消息队列,并在适当的时候处理这些消息。通过Handler,我们可以实现线程间的通信,如在主线程更新UI。 2. **Looper**: Looper是Android中的事件循环,它监听消息队列,并在接收到消息时调用Handler的handleMessage()方法。每个Looper都关联着一个线程,当在一个线程中创建Looper时,就启动了一个消息循环。 3. **MessageQueue**: MessageQueue是Android中消息传递的系统级数据结构,所有线程的消息都被添加到各自的MessageQueue中,Looper会从队列中取出并处理这些消息。 回到示例代码: 在这个名为AsyncTaskTrapActivity的Activity中,作者创建了一个名为asynctask的SimpleAsyncTask对象,然后在新线程中启动一个Runnable,该Runnable里首先调用了Looper.prepare()和Looper.myLooper()来创建一个新的Looper。这样,即使主线程在等待AsyncTask的execute()调用返回,新线程的Looper循环已经开始,导致消息队列被激活。 接着,代码设置了一个TextView(status)并在新线程中完成对它的初始化。然后主线程暂停1秒,确保新线程已经运行起来。最后,主线程通过调用asynctask.execute()启动任务。在这个过程中,主线程实际上被阻塞了,因为Looper.loop()永远不会返回,除非主线程销毁或手动中断。 当AsyncTask在新线程的doInBackground()方法中执行时,因为没有正确地关联到主线程的Looper,结果是执行任务的部分或全部可能在非UI线程中完成,这违反了Android UI线程更新UI的原则。为了纠正这个问题,应该确保AsyncTask的onPostExecute()回调在主线程中执行,以便更新UI元素。 总结,这段代码展示了一个AsyncTask滥用Handler、Looper和MessageQueue可能导致的陷阱:如果不恰当同步,主线程可能会被阻塞,影响用户体验,而且违反了Android应用开发的最佳实践。正确的做法是确保AsyncTask的UI更新操作始终在主线程中进行,避免此类问题。