在Android 4.4中,代码似乎发生了变化,导致使用AsyncTasks加载列表图标。结果是Android 4.4上的许多用户获得RejectedExecutionException
,因为超出了队列大小限制。
Code Google的聪明用户发现了这一点,并以这种方式解释:
ResolverActivity将在Android 4.4上抛出RejectedExecutionException。
我查看了最新ResolverActivity的代码并注意到在ResolveListAdapter.bindView方法中它使用了新的LoadIconTask()。execute(info),这应该是根本原因。 LoadIconTask是AsyncTask的子类,同时运行的AsyncTask太多会导致RejectedExecutionException。
可以在Android GitHub repo找到ResolverActivity更改。
我的应用目前有RejectedExecutionException
的82个堆栈跟踪,所有这些都是针对Android 4.4的。堆栈的示例开始:
java.util.concurrent.RejectedExecutionException: Task android.os.AsyncTask$3@41d44580 rejected from java.util.concurrent.ThreadPoolExecutor@41a575c0[Running, pool size = 5, active threads = 5, queued tasks = 128, completed tasks = 140]
at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2011)
at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:793)
at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1339)
at android.os.AsyncTask.executeOnExecutor(AsyncTask.java:590)
at android.os.AsyncTask.execute(AsyncTask.java:535)
at com.android.internal.app.ResolverActivity$ResolveListAdapter.bindView(ResolverActivity.java:716)
at com.android.internal.app.ResolverActivity$ResolveListAdapter.getView(ResolverActivity.java:702)
at android.widget.AbsListView.obtainView(AbsListView.java:2255)
...
有没有办法回避或处理这种变化?
答案 0 :(得分:21)
问题在于AsyncTask使用的不同执行程序,具体取决于应用程序的targetSdkVersion:
AsyncTask.execute()使用AsyncTask.THREAD_POOL_EXECUTOR。 AsyncTask.THREAD_POOL_EXECUTOR中的队列限制为128个项目。如果队列已满,则抛出RejectedExecutionException。这就是这里发生的事情
AsyncTask使用AsyncTask.SERIAL_EXECUTOR。 AsyncTask.SERIAL_EXECUTOR具有无界队列。所以在这种情况下,永远不会抛出RejectedExecutionException。
使用单独的APK与targetSdkVersion> 12和更高版本的代码,因此对于HONEYCOMB_MR2和更高版本的Android来说是首选。这将导致AsyncTask在HONEYCOMB_MR2及更高版本的Android上使用ThreadPool.SERIAL_EXECUTOR。
使用Reflection。将AsyncTask.SERIAL_EXECUTOR设为默认值。
AsyncTask.class.getMethod("setDefaultExecutor", Executor.class).invoke(null, AsyncTask.SERIAL_EXECUTOR);