Estou tentando executar duas AsyncTasks ao mesmo tempo. (A plataforma é o Android 1.5, HTC Hero.) No entanto, apenas o primeiro é executado. Aqui está um trecho simples para descrever meu problema:
public class AndroidJunk extends Activity {
class PrinterTask extends AsyncTask<String, Void, Void> {
protected Void doInBackground(String ... x) {
while (true) {
System.out.println(x[0]);
try {
Thread.sleep(1000);
} catch (InterruptedException ie) {
ie.printStackTrace();
}
}
}
};
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
new PrinterTask().execute("bar bar bar");
new PrinterTask().execute("foo foo foo");
System.out.println("onCreate() is done.");
}
}
A saída que espero é:
onCreate() is done.
bar bar bar
foo foo foo
bar bar bar
foo foo foo
E assim por diante. No entanto, o que recebo é:
onCreate() is done.
bar bar bar
bar bar bar
bar bar bar
O segundo AsyncTask nunca é executado. Se eu alterar a ordem das instruções execute (), apenas a tarefa foo produzirá saída.
Estou perdendo algo óbvio aqui e / ou fazendo algo estúpido? Não é possível executar duas AsyncTasks ao mesmo tempo?
Editar: percebi que o telefone em questão roda o Android 1.5, atualizei o problema descr. adequadamente. Não tenho esse problema com um HTC Hero executando o Android 2.1. Hummm ...
Respostas:
O AsyncTask usa um padrão de conjunto de encadeamentos para executar as coisas de doInBackground (). O problema é inicialmente (nas primeiras versões do sistema operacional Android) o tamanho do pool era apenas 1, o que significa que não há cálculos paralelos para várias tarefas AsyncTasks. Porém, mais tarde, eles corrigiram isso e agora o tamanho é 5, portanto, no máximo, 5 AsyncTasks podem ser executadas simultaneamente. Infelizmente, não me lembro em que versão exatamente eles mudaram isso.
ATUALIZAR:
Aqui está o que a API atual (2012-01-27) diz sobre isso:
DONUT é o Android 1.6, HONEYCOMB é o Android 3.0.
UPDATE: 2
Veja o comentário
kabuko
deMar 7 2012 at 1:27
.Acontece que, para APIs em que "um conjunto de threads que permite que várias tarefas operem em paralelo" é usado (a partir de 1.6 e finalizando em 3.0), o número de AsyncTasks em execução simultânea depende de quantas tarefas já foram passadas para execução, mas ainda não terminaram o seu
doInBackground()
.Isso é testado / confirmado por mim em 2.2. Suponha que você tenha um AsyncTask personalizado que durma apenas um segundo
doInBackground()
. AsyncTasks usam internamente uma fila de tamanho fixo para armazenar tarefas atrasadas. O tamanho da fila é 10 por padrão. Se você iniciar 15 suas tarefas personalizadas em uma linha, as 5 primeiras entrarão com as delesdoInBackground()
, mas o restante aguardará na fila por um encadeamento de trabalho livre. Assim que qualquer um dos 5 primeiros for concluído e, assim, liberar um thread de trabalho, uma tarefa da fila iniciará a execução. Portanto, neste caso, no máximo 5 tarefas serão executadas simultaneamente. No entanto, se você iniciar 16 suas tarefas personalizadas consecutivas, as 5 primeiras entrarão nas suasdoInBackground()
, as 10 restantes entrarão na fila, mas no dia 16 será criado um novo encadeamento de trabalho para iniciar a execução imediatamente. Portanto, neste caso, no máximo 6 tarefas serão executadas simultaneamente.Há um limite de quantas tarefas podem ser executadas simultaneamente. Como
AsyncTask
usa um executor de conjunto de encadeamentos com número máximo limitado de encadeamentos de trabalho (128) e a fila de tarefas atrasadas tem tamanho 10 fixo, se você tentar executar mais de 138 suas tarefas personalizadas, o aplicativo falharájava.util.concurrent.RejectedExecutionException
.A partir do 3.0, a API permite usar o executor do conjunto de threads personalizado por meio do
AsyncTask.executeOnExecutor(Executor exec, Params... params)
método Isso permite, por exemplo, configurar o tamanho da fila de tarefas atrasadas se o padrão 10 não for o que você precisa.Como o @Knossos menciona, existe uma opção para usar
AsyncTaskCompat.executeParallel(task, params);
na biblioteca de suporte v.4 para executar tarefas em paralelo sem se preocupar com o nível da API. Este método foi descontinuado no nível da API 26.0.0.UPDATE: 3
Aqui está um aplicativo de teste simples para jogar com o número de tarefas, execução serial versus paralela: https://github.com/vitkhudenko/test_asynctask
ATUALIZAÇÃO: 4 (obrigado @penkzhou por apontar isso)
A partir do Android 4.4
AsyncTask
se comporta de maneira diferente da descrita na seção UPDATE: 2 . Há uma correção para impedir aAsyncTask
criação de muitos threads.Antes do Android 4.4 (API 19),
AsyncTask
havia os seguintes campos:No Android 4.4 (API 19), os campos acima são alterados para isso:
Essa alteração aumenta o tamanho da fila para 128 itens e reduz o número máximo de threads ao número de núcleos da CPU * 2 + 1. Os aplicativos ainda podem enviar o mesmo número de tarefas.
fonte
AsyncTaskCompat.executeParallel(task, params);
AsyncTaskCompat.executeParallel(task, params);
agora está obsoleta #Isso permite a execução paralela em todas as versões do Android com API 4+ (Android 1.6+):
Este é um resumo da excelente resposta da Arhimed.
Certifique-se de usar a API nível 11 ou superior como destino de criação do seu projeto. No Eclipse, é isso
Project > Properties > Android > Project Build Target
. Isso não prejudica a compatibilidade com versões anteriores dos níveis mais baixos da API. Não se preocupe, você receberá erros do Lint se usar acidentalmente os recursos introduzidos posteriormenteminSdkVersion
. Se você realmente quiser usar os recursos introduzidos mais tarde do queminSdkVersion
, você pode suprimir esses erros usando anotações, mas, nesse caso, você precisa tomar cuidado sobre a compatibilidade do mesmo . Foi exatamente o que aconteceu no snippet de código acima.fonte
void startMyTask(AsyncTask<Void, ?, ?> asyncTask)
(se o seu doInBackground leva void)Tornando a sugestão @sulai mais genérica:
fonte
Apenas para incluir a atualização mais recente (ATUALIZAÇÃO 4) na resposta imaculada da @Arhimed no muito bom resumo do @sulai:
fonte
.executeOnExecutor()
agora é redundante para API> = KITKAT, sim?O exemplo de desenvolvedor do Android de carregamento de bitmaps com eficiência usa uma assíncrona personalizada (copiada do jellybean) para que você possa usar o executeOnExecutor em apis inferiores a <11
http://developer.android.com/training/displaying-bitmaps/index.html
Faça o download do código e vá para o pacote util.
fonte
Isso é possível. Minha versão do dispositivo Android é 4.0.4 e android.os.Build.VERSION.SDK_INT é 15
Eu tenho 3 spinners
E também tenho uma classe Async-Tack.
Aqui está o meu código de carregamento do girador
Isso está funcionando perfeitamente. Um por um, meus giradores carregaram. Eu não fiz o usuário executeOnExecutor.
Aqui está minha classe de tarefas assíncronas
fonte
se você quiser executar tarefas paralelas, precisará chamar o método
executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, "your task name")
após a versão Android 3.0; mas esse método não existe antes do Android 3.0 e depois da 1.6 porque é executado paralelamente por si só. Portanto, sugiro que você personalize sua própria classe AsyncTask em seu projeto, para evitar exceções em diferentes versões do Android.fonte