По состоянию на 15 февраля 2012 г. мне еще предстоит найти ни хорошее объяснение, ни причину, почему это не работает. Наиболее близким к решению является использование традиционного подхода 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 () более или менее добавляет строку в базу данных SQLite, инициализированную контекстом действия. publishProgress () вызывается обратным вызовом Interface 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);
}
Ответы:
Решение Матье подойдет для большинства, но у некоторых могут возникнуть проблемы; если не копаться во многих ссылках, предоставленных здесь или в Интернете, как объяснение Андерса Йоранссона . Я пытаюсь обобщить некоторые другие чтения прямо здесь и быстро объяснить решение, если 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)
однако был добавлен новый метод для параллельного выполнения.При последовательной обработке все задачи Async выполняются в одном потоке и, следовательно, должны ждать до завершения предыдущей задачи. Если вам нужно выполнить код немедленно, вам нужно, чтобы задачи обрабатывались параллельно в отдельных потоках.
В AsyncTask последовательное выполнение недоступно между версиями Donut и Honeycomb, а параллельное выполнение недоступно в версиях 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
(который последовательно запускает задачи в post Honeycomb).Если вы не определили,
targetSdkVersion
тоminSdkVersion
автоматически считаетсяtargetSdkVersion
.Следовательно, для параллельного запуска вашей AsyncTask на post Honeycomb вы не можете оставить
targetSdkVersion
пустым.источник
Вы должны проверить этот ответ: https://stackoverflow.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);
источник
Сделать это можно двумя способами:
Способ 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 после того, как я вызвал «выполнить» для первой: 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); }
Для вашего вопроса об обновлении: это объяснено в документации. В основном, чтобы избежать всех проблем, которые могут возникнуть из-за многопоточности, такой как взаимодействие ....
источник
Одна вещь, которую я хотел бы знать, и это может действительно решить вашу проблему, - это где вы создаете экземпляр своего класса и вызываете метод execute ()? Если вы читаете документацию по AsyncTask, обе эти операции должны выполняться в основном потоке пользовательского интерфейса. Если вы создаете свой объект и вызываете execute из какого-то другого потока, то onPreExecute может сработать, я не уверен на 100% здесь, но фоновый поток не будет создан и выполнен.
Если вы создаете экземпляр своей AsyncTask из фонового потока или какую-либо другую операцию, не выполняемую в основном потоке пользовательского интерфейса, вы можете рассмотреть возможность использования метода: Activity.runOnUiThread (Runnable)
Для вызова этого метода вам понадобится доступ к экземпляру вашего запущенного Activity, но он позволит вам запускать код в потоке пользовательского интерфейса из другого кода, который не выполняется в потоке пользовательского интерфейса.
Надеюсь, это имеет смысл. Дай мне знать, если я смогу помочь.
Дэвид
источник
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. Когда была представлена asynctask, Android позволял запускать только по одному, а когда-то позже, я не уверен, в какой версии они позволяли запускать сразу несколько asynctasks, это вызывало проблемы во многих приложениях, поэтому в Honeycomb + они вернулись только к позволяя запускать одну асинхронную задачу за раз. Если вы вручную не измените пул потоков. Надеюсь, что это прояснит кое-что для людей.
источник
Я думаю, что это SDK. У меня была такая же проблема, и после изменения целевого sdk с 15 на 11 все работает отлично.
с sdk15, даже если AsyncTask.Status находится в состоянии RUNNING, doInBackground никогда не вызывается. Я действительно думаю, что это как-то связано с потоком пользовательского интерфейса.
источник
Основываясь на ответе Матье, ниже вспомогательный класс для
AsyncTask
правильного выполнения в зависимости от версии SDK, чтобы избежать дублирования кода в вашем приложении: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);
источник