截至2012年2月15日,我还没有找到一个很好的解释,也没有理由说明这不起作用。最接近解决方案的是使用传统的Thread方法,但为什么要包含一个在Android SDK中没有(似乎)工作的类?
Evenin'SO!
我有一个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-parsing,但是当我注意到它的 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添加一行,并使用activity的上下文进行初始化。 publishProgress()由Interface ParseListener的回调调用。但是,因为除了doInBackground()中的log.v之外我甚至都没有做任何事情,所以我首先发现这甚至没有提起来。
编辑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);
}
答案 0 :(得分:158)
你应该查看这个答案:https://stackoverflow.com/a/10406894/347565以及它包含的谷歌群组的链接。
我遇到了类似的问题,仍然不清楚为什么它不起作用,但我改变了我的代码并且问题消失了:
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);
答案 1 :(得分:106)
AsyncTask().execute();
的行为已在Android版本中发生变化。之前甜甜圈 (Android:1.6 API:4)任务是从甜甜圈到 Gingerbread 连续执行的(Android:2.3 API:9)任务并行执行;因为 Honeycomb (Android:3.0 API:11)执行被切换回顺序;但是,为了并行执行,添加了一个新方法AsyncTask().executeOnExecutor(Executor)
。
在顺序处理中,所有异步任务都在单个线程中运行,因此必须在上一个任务结束之前等待。如果需要立即执行代码,则需要在不同的线程中并行处理任务。
使用AsyncTask,Donut和Honeycomb版本之间不能进行串行执行,而Donut之前并不执行并行执行。
对于Donut之后的并行处理:检查Build版本并基于该使用.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
留空。
答案 2 :(得分:7)
您可以通过两种方式实现这一目标:
方式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);
希望这会对你有所帮助。
答案 3 :(得分:6)
我遇到了同样的问题:在第一个调用“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中对此进行了解释 基本上只是为了避免可能来自多线程的所有问题,如干扰......
答案 4 :(得分:5)
我想知道的一件事,实际上可能解决你的问题,你在哪里实例化你的类的实例并调用execute()方法?如果您阅读AsyncTask的文档,则这两个操作都需要在主UI线程上进行。如果你正在创建你的对象并从其他线程调用execute,那么onPreExecute可能会触发,我不是100%肯定在这里,但后台线程不会被创建和执行。
如果要从后台线程创建AsyncTask实例,或者在主UI线程上没有进行其他操作,则可以考虑使用以下方法: Activity.runOnUiThread(Runnable)
您需要访问正在运行的Activity的实例来调用该方法,但它将允许您从UI线程上未运行的其他代码在UI线程上运行代码。
希望这是有道理的。如果我能提供更多帮助,请告诉我。
大卫
答案 5 :(得分:2)
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);
}
}
答案 6 :(得分:1)
我知道这个线程可能已经很晚了,但是有一个原因导致它无法在以后的android模拟器上运行。当asynctask被引入时,android只允许你一次运行一个,然后一段时间后,我不确定哪个版本,它们允许你一次运行多个asynctasks,这导致很多应用程序出现问题,所以在Honeycomb +中它们只恢复到允许一个asynctask一次运行。除非您手动更改线程池。 希望能为人们清除一两件事。
答案 7 :(得分:0)
我认为它是sdk。我遇到了同样的问题,在将目标sdk从15改为11之后,一切都运行良好。
使用sdk15,即使AsyncTask.Status是RUNNING,也永远不会调用doInBackground。我确实认为它与ui线程有关。
答案 8 :(得分:0)
根据Matthieu的回答,在帮助类下方根据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);