Android SDK AsyncTask doInBackground 未运行(子类)
Posted
技术标签:
【中文标题】Android SDK AsyncTask doInBackground 未运行(子类)【英文标题】:Android SDK AsyncTask doInBackground not running (subclass) 【发布时间】:2012-02-25 12:55:06 【问题描述】:截至 2012 年 2 月 15 日,我还没有找到一个很好的解释,也没有找到为什么这不起作用的原因。最接近解决方案的是使用传统的Thread 方法,但是为什么要包含一个在 Android SDK 中(似乎)不起作用的类?
晚安!
我有一个 AsyncTask 子类:
// ParseListener had a callback which was called when an item was parsed in a
// RSS-xml, but as stated further down it is not used at all right now.
private class xmlAsync extends AsyncTask<String, RSSItem, Void> implements ParseListener
执行如下:
xmlAsync xmlThread = new xmlAsync();
xmlThread.execute("http://www.nothing.com");
现在这个子类遇到了一个小错误。以前它做了一些 xml 解析,但是当我注意到它的 doInBackground() 没有被调用时,我逐行剥离了它,最后得到了这样的结果:
@Override
protected Void doInBackground(String... params)
Log.v(TAG, "doInBackground");
return null;
由于某种原因,它什么也没记录。但是,我添加了这个:
@Override
protected void onPreExecute()
Log.v(TAG, "onPreExecute");
super.onPreExecute();
并且在执行线程时确实记录了该行。 所以不知何故 onPreExecute() 被调用,而不是 doInBackground()。我有另一个 AsyncTask 同时在后台运行,它工作得很好。
我目前在靠近北极的模拟器、SDK 版本 15、Eclipse、Mac OS X 10.7.2 上运行该应用程序。
编辑:
@Override
protected void onProgressUpdate(RSSItem... values)
if(values[0] == null)
// activity function which merely creates a dialog
showInputError();
else
Log.v(TAG, "adding "+values[0].toString());
_tableManager.addRSSItem(values[0]);
super.onProgressUpdate(values);
_tableManager.addRSSItem() 或多或少地向 SQLiteDatabase 添加一行,并使用活动的上下文进行初始化。 publishProgress() 由接口 ParseListener 的回调调用。但是,由于我什至什么都不做,除了 log.v 在 doInBackground() 中,我首先发现这甚至没有必要提出。
编辑 2:
好的,为了清楚起见,这是另一个 AsyncTask,在同一个活动中执行并且工作正常。
private class dbAsync extends AsyncTask<Void, RSSItem, Void>
Integer prevCount;
boolean run;
@Override
protected void onPreExecute()
run = true;
super.onPreExecute();
@Override
protected Void doInBackground(Void... params)
// TODO Auto-generated method stub
run = true;
prevCount = 0;
while(run)
ArrayList<RSSItem> items = _tableManager.getAllItems();
if(items != null)
if(items.size() > prevCount)
Log.v("db Thread", "Found new item(s)!");
prevCount = items.size();
RSSItem[] itemsArray = new RSSItem[items.size()];
publishProgress(items.toArray(itemsArray));
SystemClock.sleep(5000);
return null;
@Override
protected void onProgressUpdate(RSSItem... values)
ArrayList<RSSItem> list = new ArrayList<RSSItem>();
for(int i = 0; i < values.length; i++)
list.add(i, values[i]);
setItemsAndUpdateList(list);
super.onProgressUpdate(values);
@Override
protected void onCancelled()
run = false;
super.onCancelled();
编辑 3:
叹气,抱歉我不擅长提问。但这里是任务的初始化。
xmlAsync _xmlParseThread;
dbAsync _dbLookup;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
_dbLookup = new dbAsync();
_dbLookup.execute();
_xmlParseThread = new xmlAsync();
_xmlParseThread.execute("http://www.nothing.com", null);
【问题讨论】:
活动是否可能在任务完成之前完成? 极不可能。在那种情况下,我的其他线程将无法正常运行?而且我现在只有一项活动。 我的应用程序有同样的问题 - doInBackground 要么没有被调用,要么被调用了很长的延迟。这是我有限的观察:完全相同的代码在 android 2.3.3 智能手机和 Android 2.3.3 模拟器上完美运行,但在 Android 4.0.3 平板电脑和一堆 Android 4.x.x 模拟器上存在这个问题。很容易得出结论,这个问题是在较新版本的 Android 中引入的。 对不起,但我忘了提到这个问题只发生在 Activity 的第二个 AsyncTask 第一个 AsyncTask 总是工作正常。 Hong,你试过马修的回答吗?我大部分时间都在使用 Android 游戏 ATM 并且有一段时间没有使用它,所以我无法判断他的答案是否真的有效。如果它不适合你,那么我接受他的回答可能很糟糕...... 【参考方案1】:您应该查看此答案:https://***.com/a/10406894/347565 以及其中包含的 google 群组链接。
我遇到了和你类似的问题,仍然不清楚为什么它不起作用,但是我像这样更改了我的代码,问题就消失了:
ASyncTask<Void,Void,Void> my_task = new ASyncTask<Void,Void,Void>() ... ;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
my_task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[])null);
else
my_task.execute((Void[])null);
【讨论】:
我在回顾这篇文章时一直很糟糕;我早就离开了这个项目。我会接受这个作为答案,因为人们似乎说它有效。 这对我有用,但我希望我明白为什么。它在执行之前运行良好,然后它停止了。我正在做的一件事是在同一个异步任务的 onPostExecute 中启动一个新的异步任务(即我递归调用它)也许这与问题有关? 我认为这应该给你所有你需要的解释:commonsware.com/blog/2012/04/20/… @Matthieu : 先生,我真的非常感谢你!!!几个小时以来,我一直在努力解决这个问题,而您的解决方案使一切都像魅力一样工作!非常感谢您的精彩回答。我希望我能投不止一个赞成票! @joao2fast4u web.archive.org/web/20131219080911/http://www.jayway.com/2012/…【参考方案2】:Matthieu 的解决方案适用于大多数人,但有些人可能会遇到问题;除非挖掘此处提供或来自网络的许多链接,例如Anders Göransson 的解释。 如果 executeOnExecutor 仍在单线程中工作,我正在尝试总结其他一些阅读并快速解释解决方案...
AsyncTask().execute();
的行为在 Android 版本中有所改变。在 Donut (Android:1.6 API:4) 任务被串行执行之前,从 Donut 到 Gingerbread (Android:2.3 API:9) 任务并行执行;由于 Honeycomb (Android:3.0 API:11) 执行已切换回顺序;但是,为并行执行添加了一个新方法 AsyncTask().executeOnExecutor(Executor)
。
在顺序处理中,所有异步任务都在单个线程中运行,因此必须在前一个任务结束之前等待。如果您需要立即执行代码,则需要在单独的线程中并行处理任务。
Donut 和 Honeycomb 版本之间不支持 AsyncTask 串行执行,而在 Donut 之前不支持并行执行。
对于 Donut 之后的并行处理:检查构建版本并在此基础上使用 .execute() 或 .executeOnExecutor() 方法。以下代码可以帮助...
AsyncTask<Void,Void,Void> myTask = new AsyncTask<Void,Void,Void>() ... ; // ... your AsyncTask code goes here
if (Build.VERSION.SDK_INT>=Build.VERSION_CODES.HONEYCOMB)
myTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
else
myTask.execute();
NOTE:
函数.executeOnExecutor()
检查项目的targetSdkVersion
是否小于或等于HONEYCOMB_MR1
(Android:2.1 API:7) 然后强制执行程序为THREAD_POOL_EXECUTOR
(按顺序运行任务在蜂窝后)。
如果您尚未定义targetSdkVersion
,则minSdkVersion
将自动被视为targetSdkVersion
。
因此,要在后 Honeycomb 上并行运行 AsyncTask,您不能将 targetSdkVersion
留空。
【讨论】:
很好的答案。虽然 Matthieu 没有错,但我接受了这一点,因为您添加了一堆重要信息。 @Nashe 非常感谢。这真的很有帮助。我与同样的问题斗争了 3 天。再次感谢:) 拯救了我的一天!希望这个答案更容易找到。 嘿@Nashe,我的问题有点尴尬。在今天之前,我在 AsyncTask 上使用 .execute() 方法,并且代码运行良好。但是今天我遇到了问题 - 控件没有进入 doInBackground() 方法。尽管您提供的解决方案有效,但我很困惑以前没有解决方案它是如何工作的。我以前和现在都使用同一组设备。 为什么会这样?为什么它不能按预期工作? :(【参考方案3】:您可以通过两种方式做到这一点:
方式 1:
if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.HONEYCOMB) // Above Api Level 13
asyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
else // Below Api Level 13
asyncTask.execute();
如果 方式 1 不适合您,请尝试 方式 2。
方式 2:
int mCorePoolSize = 60;
int mMaximumPoolSize = 80;
int mKeepAliveTime = 10;
BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<Runnable>(mMaximumPoolSize);
Executor mCustomThreadPoolExecutor = new ThreadPoolExecutor(mCorePoolSize, mMaximumPoolSize, mKeepAliveTime, TimeUnit.SECONDS, workQueue);
asyncTask.executeOnExecutor(mCustomThreadPoolExecutor);
希望这会对你有所帮助。
【讨论】:
超级花花公子,但下一个使用 AsyncTask.THREAD_POOL_EXECUTOR 的后续异步任务失败了,所以我想我需要在整个项目中使用 CustomExecutor 进行更改:( @vinu,我建议你使用常用的异步任务和常用的方法来执行AsyncTask。希望这会对你有所帮助。 嘿,这对我帮助很大!谢谢!【参考方案4】:我遇到了同样的问题:在我对第一个 AsyncTask 调用“execute”之后,不能再执行第二个 AsyncTask:doInBackground 只为第一个调用。
要回答为什么会发生这种情况,请查看answer(不同的行为取决于 SDK)
但是,对于您的情况,可以使用 executeOnExecutor(从 3.0 开始使用 4.0.3 为我工作)来避免这个障碍,但要注意线程池大小和排队的限制。
你能试试这样的吗:
xmlAsync _xmlParseThread;
dbAsync _dbLookup;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
_dbLookup = new dbAsync();
_dbLookup.execute();
_xmlParseThread = new xmlAsync();
_xmlParseThread.executeOnExecutor(_dbLookup.THREAD_POOL_EXECUTOR
,"http://www.nothing.com", null);
对于您的更新问题:docs 中对此进行了解释 基本上只是为了避免可能来自多线程的所有问题,比如相互引用......
【讨论】:
【参考方案5】:我想知道的一件事,它实际上可能会解决您的问题,您在哪里实例化您的类的实例并调用 execute() 方法?如果您阅读了 AsyncTask 的文档,那么这两个操作都需要在主 UI 线程上进行。如果您正在创建对象并从其他线程调用执行,那么 onPreExecute 可能会触发,我在这里不是 100% 确定,但不会创建和执行后台线程。
如果您是从后台线程创建 AsyncTask 的实例,或者其他一些未在主 UI 线程上进行的操作,您可以考虑使用以下方法: Activity.runOnUiThread(Runnable)
您需要访问正在运行的 Activity 的实例才能调用该方法,但它允许您从未在 UI 线程上运行的其他代码在 UI 线程上运行代码。
希望这是有道理的。如果我能提供更多帮助,请告诉我。
大卫
【讨论】:
在你的答案中添加这个帖子有一个有趣的答案***.com/questions/4080808/…。 感谢您的精彩回答!我提高了这一点,因为我认为这可能是一个常见的 AsyncTask 初学者问题。唉,这不是这个问题的正确答案。这两个类都在主 UI 线程上运行的活动的 onCreate() 中实例化。我在这个项目中只有一项活动。 @manjusg 我一直认为它与 AsyncTask 不稳定有关,当同时运行多个时可能更是如此。如果有,为什么? 我真的不知道 SO 有什么政策可以连续 3 次快速发布,但我在另一个线程中发现了这个...foo.jasonhudgins.com/2010/05/limitations-of-asynctask.html"AsyncTask 使用静态内部工作队列10 个元素的硬编码限制。”这可能证明了一些事情,但我只有两个 AsyncTask 子类的实例!我真的很想避免使用普通的线程方法,因为最终会在 dere 中完成大量解析。【参考方案6】:Android 是残酷的!我无法相信这一点,从今天到今天发生了多么糟糕的实现。一天是一个线程,下一个是 5,另一个是 128。
无论如何,这里的 AsyncTask 替代品几乎下降了。如果您愿意,您甚至可以将其称为 AsyncTask,但为避免混淆,将其称为 ThreadedAsyncTask。您需要调用 executeStart() 而不是 execute,因为 execute() 是最终的。
/**
* @author Kevin Kowalewski
*
*/
public abstract class ThreadedAsyncTask<Params, Progress, Result> extends AsyncTask<Params, Progress, Result>
public AsyncTask<Params, Progress, Result> executeStart(Params... params)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
return executePostHoneycomb(params);
else
return super.execute(params);
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
private AsyncTask<Params, Progress, Result> executePostHoneycomb(Params... params)
return super.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, params);
【讨论】:
等等,你不是说某些版本的 Android 将异步操作限制为一个线程,是吗?那将是非常愚蠢的。 (我已经离开 Android 游戏一段时间了。:)) 是的,在 Android 3.0+ 上,如果您不使用 AsyncTask.THREAD_POOL_EXECUTOR,您只会获得一个线程池。自己尝试一下,两个 AsyncTask,然后睡在一个 doInBackground 中。来自 Android AsyncTask 文档:“从 HONEYCOMB 开始,任务在单个线程上执行,以避免并行执行导致的常见应用程序错误。”【参考方案7】:我知道这对于线程来说可能真的很晚了,但是它不能在以后的 android 模拟器上工作是有原因的。当 asynctask 被引入时,android 只允许你一次运行一个,然后一段时间后,我不确定是哪个版本,他们允许你一次运行多个 asynctask,这导致了很多应用程序的问题,所以在 Honeycomb+ 他们恢复为只允许一次运行一个异步任务。除非你手动更改线程池。 希望能为人们解决一两件事。
【讨论】:
【参考方案8】:我认为它是 sdk。我遇到了同样的问题,将目标 sdk 从 15 更改为 11 后,一切正常。
使用 sdk15,即使 AsyncTask.Status 为 RUNNING,doInBackground 也不会被调用。我确实认为这与 ui 线程有关。
【讨论】:
我既不能否认也不能确认,因为我现在真的没有时间测试它。我只能说我使用的是 SDK 15,所以很有可能。【参考方案9】:根据 Matthieu 的回答,在 helper 类下方根据 SDK 版本正确执行您的 AsyncTask
以避免在您的应用程序中重复代码:
import android.annotation.SuppressLint;
import android.os.AsyncTask;
import android.os.Build;
public class AsyncTaskExecutor<Params, Progress, Result>
@SuppressLint("NewApi")
public AsyncTask<Params, Progress, Result> execute(final AsyncTask<Params, Progress, Result> asyncTask, final Params... params)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
return asyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, params);
else
return asyncTask.execute(params);
使用示例:
public class MyTask extends AsyncTask<Void, Void, List<String>>
...
final MyTask myTask = new MyTask();
new AsyncTaskExecutor<Void, Void, List<String>>().execute(myTask);
【讨论】:
以上是关于Android SDK AsyncTask doInBackground 未运行(子类)的主要内容,如果未能解决你的问题,请参考以下文章
Android SDK AsyncTask doInBackground 未运行(子类)
android中 如果要你来设计AsyncTask,你怎么设计