Android SDK AsyncTask doInBackground没有运行(子类)

截至2012年2月15日,我还没有find一个很好的解释,也没有理由为什么这不起作用。 最接近解决scheme的是使用传统的线程方法,但是为什么包含一个类似的东西(似乎不)在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"); 

现在这个小类遇到了一点小错误。 以前它做了一些xmlparsing,但是当我注意到doInBackground()没有被调用的时候,我一行一行地把它解下来,最后以这个结尾:

 @Override protected Void doInBackground(String... params) { Log.v(TAG, "doInBackground"); return null; } 

由于某种原因,没有logging。 不过,我补充说:

 @Override protected void onPreExecute() { Log.v(TAG, "onPreExecute"); super.onPreExecute(); } 

并且该行在执行线程时确实被logging下来。 所以不知何故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()或多或less地向SQLiteDatabase添加一行,并使用该活动的上下文进行初始化。 publishProgress()由Interface ParseListener的callback调用。 然而,因为我甚至没有做任何事情,除了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); } 

Matthieu的解决scheme对大多数人来说都能正常工作,但有些人可能会面临问题; 除非在这里或从网上提供的许多链接挖掘,像安德斯·格兰松的解释。 我正在尝试总结一些其他的阅读在这里,并迅速解释如果executeOnExecutor仍然在单线程工作的解决scheme…

AsyncTask().execute();行为AsyncTask().execute(); 已经通过Android版本改变。 在Donut (Android:1.6 API:4)任务被连续执行之前,从DonutGingerbread (Android:2.3 API:9)执行任务并行; 自Honeycomb (Android:3.0 API:11)执行被切换回顺序; 一个新的方法AsyncTask().executeOnExecutor(Executor)然而,被添加为并行执行。

在顺序处理中,所有Async任务都在单个线程中运行,因此必须等待上一个任务结束之前。 如果您需要立即执行代码,则需要在单独的线程中并行处理任务。

在Donut和Honeycomb版本之间,AsyncTask串行执行不可用,而在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 (在后蜂巢中按顺序运行任务)。
如果您尚未定义targetSdkVersionminSdkVersion会自动被视为targetSdkVersion
因此,对于在发布Honeycomb时并行运行AsyncTask,您不能将targetSdkVersion留空。

编辑: Android支持库现在包括助手类AsyncTaskCompat ,它可以照顾API的变化,使您的代码更小/更简单。 这是语法…

 AsyncTask<Void,Void,Void> myAsyncTask = new AsyncTask<Void,Void,Void>() { ... }; // ... your AsyncTask AsyncTaskCompat.executeParallel( myAsyncTask, Params ); 

其中myAsyncTask是您定义的任务,或者您可以在此语句中执行new AsyncTask()Params是要发送给AsyncTask的参数,或者您可以发送null

AsyncTaskCompat在API级别26.0.0-alpha1中被弃用

你应该检查这个答案: 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); 

我有同样的问题:我不能执行第二个AsyncTask之后,我第一个调用“执行”:doInBackground只为第一个调用。

要回答为什么发生这种情况,请检查此答案 (根据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); } 

对于您的更新问题:这是在文档中解释基本上只是为了避免可能来自multithreading,如干涉所有问题….

有一件事我想知道,它可能确实解决了你的问题,你是在哪里实例化你的类的实例并调用execute()方法? 如果您阅读AsyncTask的文档,那么这两个操作都需要在主UI线程上进行。 如果你正在创build你的对象,并从其他线程调用执行,那么onPreExecute可能会触发,我不是100%确定在这里,但后台线程将不会被创build和执行。

如果从后台线程创buildAsyncTask实例,或者在主UI线程上没有发生其他操作,可以考虑使用以下方法: Activity.runOnUiThread(Runnable)

您需要访问正在运行的Activity的实例来调用该方法,但是它将允许您从UI线程上未运行的其他代码在UI线程上运行代码。

希望是有道理的。 让我知道如果我可以帮助更多。

大卫

你可以通过两种方式来做到这一点:

方式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); 

希望这会帮助你。

Android是残酷的! 我无法相信这一点,从一天到今天都在发生什么样的事情。 有一天它是一个单一的线程,下一个是另一个是128。

无论如何,这里是股票AsyncTask几乎下降替代。 你甚至可以把它叫做AsyncTask,但是为​​了避免混淆它,叫做ThreadedAsyncTask。 你需要调用executeStart()而不是execute,因为execute()是final的。

 /** * @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模拟器。 当引入的asynctask只允许你一次运行一个,然后某个时候,我不知道哪个版本,他们允许你一次运行多个asynctasks,这导致了很多的应用程序的问题,所以在蜂窝+他们只恢复到允许一个asynctask一次运行。 除非您手动更改线程池。 希望能为人们解决一两件事情。

我认为它的SDK。 我也有同样的问题,在将目标sdk从15更改为11之后,一切正常。

与sdk15,即使AsyncTask.Status正在运行,doInBackground永远不会被调用。 虽然我认为它与UI线程有关。

根据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);