Em 15/02/2012, ainda não encontrei uma boa explicação para nem uma razão para que isso não funcione. O mais próximo de uma solução é usar a abordagem tradicional de Thread , mas então por que incluir uma classe que (parece) não funciona no Android SDK?
Tarde ASSIM!
Eu tenho uma subclasse 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
Isso é executado assim:
xmlAsync xmlThread = new xmlAsync();
xmlThread.execute("http://www.nothing.com");
Agora, essa subclasse deu um pequeno erro. Anteriormente, ele fazia uma análise de xml, mas quando percebi que doInBackground () não era chamado , eliminei , linha por linha, finalmente terminando apenas com isto:
@Override
protected Void doInBackground(String... params)
{
Log.v(TAG, "doInBackground");
return null;
}
Que, por algum motivo, não registrou nada. No entanto, adicionei isto:
@Override
protected void onPreExecute()
{
Log.v(TAG, "onPreExecute");
super.onPreExecute();
}
E essa linha é de fato registrada ao executar o thread. Então, de alguma forma, onPreExecute () é chamado, mas não doInBackground () . Tenho outra AsyncTask em execução em segundo plano ao mesmo tempo que funciona muito bem.
Atualmente, estou executando o aplicativo em um emulador, SDK versão 15, Eclipse, Mac OS X 10.7.2, próximo ao Pólo Norte.
EDITAR:
@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 () adiciona mais ou menos uma linha a um SQLiteDatabase, inicializado com o contexto da atividade. publishProgress () é chamado pelo retorno de chamada do Interface ParseListener. No entanto, como eu nem mesmo faço nada, exceto log.v em doInBackground (), primeiro achei isso desnecessário até mesmo abrir.
EDIT 2:
Tudo bem, só para ficar bem claro, essa é a outra AsyncTask, executando na mesma atividade e funcionando perfeitamente.
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();
}
}
EDITAR 3:
Sigh, desculpe, eu sou ruim em fazer perguntas. Mas aqui está a inicialização do Tasks.
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);
}
Respostas:
A solução de Matthieu funcionará bem para a maioria, mas alguns podem enfrentar problemas; a menos que procure em muitos links fornecidos aqui ou na web, como Anders Göransson a explicação de . Estou tentando resumir algumas outras leituras aqui e explicar rapidamente a solução se executeOnExecutor ainda estiver funcionando em um único thread ...
O comportamento do
AsyncTask().execute();
mudou nas versões do Android. Antes do Donut (Android: 1.6 API: 4), as tarefas eram executadas em série, do Donut ao Gingerbread (Android: 2.3 API: 9), as tarefas paralelo; uma vez que a execução do Honeycomb (Android: 3.0 API: 11) foi alternada de volta para sequencial; um novo métodoAsyncTask().executeOnExecutor(Executor)
, entretanto, foi adicionado para execução paralela.No processamento sequencial, todas as tarefas Async são executadas em um único thread e, portanto, têm que esperar antes que a tarefa anterior termine. Se você precisa executar o código imediatamente, precisa que as tarefas sejam processadas em paralelo em threads separados.
Com AsyncTask, a execução serial não está disponível entre as versões Donut e Honeycomb, enquanto a execução paralela não está disponível antes de Donut.
Para processamento paralelo após Donut: Verifique a versão Build e com base nesse método use .execute () ou .executeOnExecutor (). O código a seguir pode ajudar ...
NOTE:
A função.executeOnExecutor()
verifica se otargetSdkVersion
projeto é menor ou igual aHONEYCOMB_MR1
(Android: 2.1 API: 7) e então força o executor a serTHREAD_POOL_EXECUTOR
(que executa tarefas sequencialmente no pós-Honeycomb).Se você não definiu um,
targetSdkVersion
entãominSdkVersion
é automaticamente considerado otargetSdkVersion
.Portanto, para executar sua AsyncTask em paralelo no post Honeycomb, você não pode deixar
targetSdkVersion
vazio.fonte
Você deve verificar esta resposta: https://stackoverflow.com/a/10406894/347565 e o link para grupos do google que ele inclui.
Eu tive um problema parecido com o seu, ainda não sei por que não está funcionando, mas mudei meu código assim e o problema desapareceu:
fonte
Você pode fazer isso de duas maneiras:
Caminho 1 :
Caso a maneira 1 não funcione para você, tente a maneira 2 .
Caminho 2 :
Espero que isso ajude você.
fonte
Eu tive o mesmo problema: não consigo executar uma segunda AsyncTask depois de chamar "execute" em uma primeira: doInBackground só é chamado para a primeira.
Para responder por que isso acontece, verifique esta resposta (comportamento diferente dependendo do SDK)
No entanto, para o seu caso, esse obstáculo pode ser evitado usando executeOnExecutor (disponível a partir de 3.0 funcionou para mim usando 4.0.3), mas tome cuidado com as limitações de tamanho e enfileiramento do pool de threads.
Você pode tentar algo assim:
Para a sua pergunta de atualização: é explicado na documentação Basicamente apenas para evitar todos os problemas que podem surgir de multithreading como intereferência ....
fonte
Uma coisa que eu gostaria de saber, e isso pode realmente corrigir seu problema, é onde você está instanciando a instância de sua classe e chamando o método execute ()? Se você ler a documentação para AsyncTask, ambas as operações precisam ocorrer no thread de IU principal. Se você estiver criando seu objeto e chamando execute de algum outro thread, então onPreExecute pode disparar, não estou 100% certo aqui, mas o thread de segundo plano não será criado e executado.
Se você estiver criando a instância de sua AsyncTask a partir de um thread de segundo plano ou alguma outra operação que não esteja ocorrendo no thread de IU principal, poderá considerar o uso do método: Activity.runOnUiThread (Runnable)
Você precisaria de acesso a uma instância de sua Activity em execução para chamar esse método, mas isso permitirá que você execute código no UI thread a partir de algum outro código que não está sendo executado no UI thread.
Espero que isso faça sentido. Deixe-me saber se eu puder ajudar mais.
David
fonte
Android é brutal! Eu não posso acreditar nisso, que implementação instável que muda de um dia para o outro. Um dia é um único thread, no outro é 5 e o outro é 128.
De qualquer forma, aqui está quase uma queda na substituição do estoque AsyncTask. Você pode até chamá-lo de AsyncTask se quiser, mas para evitar confusão é chamado de ThreadedAsyncTask. Você precisa chamar executeStart () em vez de execute porque execute () é final.
fonte
Sei que pode ser muito tarde para o tópico, mas há um motivo pelo qual ele não funcionará em emuladores Android posteriores. Quando asynctask foi introduzido, o Android só permitia que você executasse um por vez, então algum tempo depois, não tenho certeza de qual versão, eles permitiam que você executasse várias tarefas async ao mesmo tempo, isso causou problemas em muitos aplicativos e, portanto, no Honeycomb + eles voltaram para apenas permitindo que uma tarefa assíncrona seja executada por vez. A menos que você altere manualmente o pool de threads. Espero que isso esclareça uma ou duas coisas para as pessoas.
fonte
Eu acho que é o SDK. Eu tive o mesmo problema, e depois de mudar o alvo sdk de 15 para 11, tudo funciona perfeitamente.
com sdk15, mesmo que AsyncTask.Status esteja RUNNING, doInBackground nunca é chamado. Eu acho que tem algo a ver com o tópico da interface do usuário.
fonte
Com base na resposta de Matthieu, segue abaixo uma classe auxiliar para executar seu
AsyncTask
corretamente dependendo da versão do SDK para evitar a duplicação de código em seu aplicativo:Exemplo de uso:
...
fonte