Explicação detalhada de 6 implementações de tarefas assíncronas do Android

Explicação detalhada de 6 implementações de tarefas assíncronas do Android


O encadeamento da interface do usuário do Android (encadeamento principal) tem várias características:

  • A exibição da interface do usuário só pode ser operada no encadeamento da interface do usuário, não em subencadeamentos.
  • Operações demoradas não podem ser executadas no thread da interface do usuário, caso contrário, o thread da interface do usuário será bloqueado, causando problemas como ANR e congelamento.

No desenvolvimento do Android, geralmente usamos tarefas assíncronas para processar algumas operações demoradas. Por exemplo, em tal cenário, o thread filho executa uma tarefa assíncrona em segundo plano. Durante o processo da tarefa, o processo de interface do usuário precisa exibir o progresso. Neste momento, precisamos de uma ferramenta para atender a esse requisito. O sistema Android fornece aos desenvolvedores uma classe de tarefa assíncrona (AsyncTask) para implementar as funções mencionadas acima, ou seja, executará tarefas de computação em um sub-thread e, ao mesmo tempo, obterá a oportunidade de atualizar a interface do aplicativo por meio do loop de mensagem do thread principal.

Quais são as tarefas assíncronas comumente usadas no desenvolvimento do Android?

1. Criado usando Thread

A maneira mais direta é usar a classe Thread fornecida pelo Java para criar threads para obter assincronia.

Para saber como criar threads, consulte "Resumo de três maneiras de criar threads em Java" .

2. Thread + Looper + manipulador

O Android fornece um mecanismo Handler para comunicação entre threads, podemos usar o método assíncrono mais básico do Android: Thread + Looper + handler para executar tarefas assíncronas.

Para os princípios dos mecanismos relacionados ao manipulador, consulte: "Mecanismo de comunicação do thread do manipulador: combate real, princípios e otimização de desempenho!" "

Código de amostra:

Handler mHandler = newHandler(){
    @Override
    publicvoid handleMessage(Message msg){
        if(msg.what == 1){
            textView.setText("Task Done!!");
        }
    }
};
mRunnable = new Runnable() {
    @Override
    publicvoid run() {
        SystemClock.sleep(1000);    // 耗时处理
        mHandler.sendEmptyMessage(1);  
    }
};
private void startTask(){
    new Thread(mRunnable).start();
}

vantagem:

  • A operação é simples e não há custo de aprendizado.

deficiência:

  • O código é mal padronizado e difícil de manter.
  • Cada operação abrirá um thread anônimo e a sobrecarga do sistema é grande.

3. AsyncTask

Uma classe assíncrona relativamente leve que encapsula o pool de threads do FutureTask, ArrayDeque e Handler para agendamento. AsyncTask é usado principalmente para interação contínua entre o plano de fundo e a interface.

Vamos dar uma olhada na definição da classe abstrata AsyncTask. Quando definimos uma classe para herdar a classe AsyncTask, precisamos especificar três parâmetros genéricos para ela:

AsyncTask <Params, Progress, Result>

  • Params: Este genérico especifica o tipo de parâmetros que passamos para a execução da tarefa assíncrona.
  • Progresso: esse tipo genérico especifica o tipo de parâmetro que nossa tarefa assíncrona retornará ao thread da interface do usuário quando o andamento da execução for executado.
  • Resultado: o tipo do resultado retornado ao thread de interface do usuário após a execução da tarefa assíncrona especificada por esse tipo genérico.

Quando definimos uma classe que herda a classe AsyncTask, devemos especificar os tipos desses três tipos genéricos, caso não sejam especificados, todos serão escritos como void.

Vejamos um exemplo oficial:

private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
     protected Long doInBackground(URL... urls) {
         int count = urls.length;
         long totalSize = 0;
         for (int i = 0; i < count; i++) {
             totalSize += Downloader.downloadFile(urls[i]);
             publishProgress((int) ((i / (float) count) * 100));
             // Escape early if cancel() is called
             if (isCancelled()) break;
         }
         return totalSize;
     }
     protected void onProgressUpdate(Integer... progress) {
         setProgressPercent(progress[0]);
     }
     protected void onPostExecute(Long result) {
         showDialog("Downloaded " + result + " bytes");
     }
}

Ao usá-lo, você só precisa integrar o AsyncTask, criar um objeto e chamar execute para executar:

new DownloadFilesTask().execute(url1, url2, url3);

Execute a lógica demorada no método doInBackground(Params…) e, em seguida, atualize o resultado de volta para o componente de interface do usuário em onPostExecute(Result)

Entre os principais métodos de AsyncTask, o método doInBackground é executado no thread filho e os métodos execute, onPreExecute, onProgressUpdate e onPostExecute são executados no thread de interface do usuário.

Notas sobre o uso de AsyncTask

  • A instância de AsyncTask deve ser criada no UI Thread.
  • O método execute de um AsyncTask só pode ser chamado do thread de interface do usuário.
  • Os quatro métodos substituídos de AsyncTask são chamados automaticamente pelo sistema e não devem ser chamados manualmente.
  • Cada AsyncTask só pode ser executado uma vez, várias execuções causarão uma exceção.
  • Dos quatro métodos de AsyncTask, apenas o método doInBackground é executado em outros encadeamentos e os outros três métodos são executados no encadeamento da interface do usuário, o que significa que os outros três métodos podem executar operações de atualização da interface do usuário.
  • AsyncTask é executada serialmente por padrão.Se a execução paralela for necessária, use o método executeOnExecutor da interface.

vantagem:

  • Estrutura clara, fácil de usar, adequada para interação de tarefas em segundo plano.
  • A prioridade do encadeamento assíncrono foi definida por padrão: THREAD_PRIORITY_BACKGROUND, que não aproveitará recursos com o encadeamento da interface do usuário.

deficiência:

  • A estrutura é um pouco complicada e o código é mais.
  • Cada AsyncTask só pode ser executado uma vez e uma exceção ocorrerá se chamada várias vezes.
  • AsyncTask mantém um pool de threads em todo o sistema Android, que pode ser interrompido por tarefas de outros processos e reduzir a eficiência.

Nota: Para o princípio do AsyncTask e mais detalhes, consulte "Você realmente sabe como usar o AsyncTask?" Combate real, princípio, melhor prática! (Android Q)" .

4. HandlerThread

HandlerThread é uma classe de encadeamento com seu próprio loop de mensagem Looper. A maneira de lidar com tarefas assíncronas é a mesma que Thread + Looper + Handler.

vantagem:

  • Simples, o loop de mensagem Looper de threads comuns é implementado internamente.
  • Múltiplas tarefas podem ser executadas em série.
  • Ele tem sua própria fila de mensagens interna e não bloqueia o thread da interface do usuário.

deficiência:

  • Se não houver nenhum resultado retornado à interface, ele precisa ser tratado por si mesmo.
  • Quando há muitas mensagens, é fácil causar bloqueio.
  • Há apenas um processamento de thread, que é menos eficiente.
  • Prioridade do encadeamento A prioridade padrão é THREAD_PRIORITY_DEFAULT, que é fácil de antecipar recursos do encadeamento da interface do usuário.

Nota: Para mais detalhes, consulte: "Análise do princípio HandlerThread, combate real, melhor prática!" " .

5. IntençãoServiço

IntentService herda da classe Service e é usado para iniciar uma tarefa de serviço assíncrona.Ele implementa tarefas de processamento assíncrono internamente por meio de HandlerThread.

Vejamos o método principal do IntentService:

    @Override
    public void onCreate() {
        // TODO: It would be nice to have an option to hold a partial wakelock
        // during processing, and to have a static startService(Context, Intent)
        // method that would launch the service & hand off a wakelock.

        super.onCreate();
        HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
        thread.start();

        mServiceLooper = thread.getLooper();
        mServiceHandler = new ServiceHandler(mServiceLooper);
    }

    @Override
    public void onStart(@Nullable Intent intent, int startId) {
        Message msg = mServiceHandler.obtainMessage();
        msg.arg1 = startId;
        msg.obj = intent;
        mServiceHandler.sendMessage(msg);
    }

    private final class ServiceHandler extends Handler {
        public ServiceHandler(Looper looper) {
            super(looper);
        }

        @Override
        public void handleMessage(Message msg) {
            onHandleIntent((Intent)msg.obj);
            stopSelf(msg.arg1);
        }
    }

vantagem:

  • Você só precisa herdar IntentService e pode processar tarefas do tipo Intent de forma assíncrona no método onHandlerIntent.
  • Após o término da tarefa, o IntentService irá parar sozinho, não sendo necessário chamar stopService manualmente.
  • Ele pode processar várias solicitações de intenção e executar várias tarefas sequencialmente.
  • IntentService é herdado de Service e tem prioridade de serviço em segundo plano.

deficiência:

  • Necessidade de iniciar o serviço para executar tarefas assíncronas, não adequadas para processamento de tarefas simples.
  • Tarefas assíncronas são implementadas por HandlerThread, que só pode processar tarefas em um único thread e sequencialmente.
  • Não há interface de volta para o thread de interface do usuário.

6. Use o pool de threads para lidar com tarefas assíncronas

Use os métodos estáticos newCachedThreadPool(), newFixedThreadPool(), newSingleThreadExecutor() e formas sobrecarregadas de Executors para instanciar a interface ExecutorService para obter o objeto pool de encadeamentos.

  • Pool dinâmico de threads newCachedThreadPool(): Crie novos threads de acordo com as necessidades. Quando a demanda for grande, mais serão criados. Quando a demanda for pequena, a JVM liberará lentamente os threads redundantes.
  • Um número fixo de pools de threads newFixedThreadPool(): Há uma fila de bloqueio de tarefas dentro. Suponha que haja 2 threads no pool de threads e 4 tarefas sejam enviadas, então as duas últimas tarefas são colocadas na fila de bloqueio de tarefas, mesmo que a primeira 2 tarefas suspensas Ou se estiver bloqueada, as duas últimas tarefas não serão executadas a menos que as duas primeiras tenham sido executadas.
  • Single-threaded newSingleThreadExecutor(): Um pool de threads de thread único, esse pool de threads pode reiniciar um thread depois que o thread morrer (ou quando ocorrer uma exceção) para substituir o thread original e continuar a executar.

vantagem:

  • A criação e destruição de encadeamentos é mantida pelo pool de encadeamentos, que realiza a reutilização de encadeamentos, reduzindo assim a sobrecarga de criação e destruição de encadeamentos.
  • É adequado para executar um grande número de tarefas assíncronas e melhorar o desempenho.
  • Alta flexibilidade, você pode controlar livremente o número de threads.
  • Boa escalabilidade, pode ser expandida de acordo com as necessidades reais.

deficiência:

  • O código é um pouco mais complicado.
  • O próprio pool de threads consome recursos do sistema até certo ponto.
  • Quando há muitos threads, o custo de alternar entre os threads será muito alto, o que prejudicará seriamente o desempenho.
  • Cada thread consome pelo menos 1040 KB de memória e o número de threads no pool de threads precisa ser controlado dentro de um determinado intervalo.
  • A prioridade do encadeamento é herdada. Se um conjunto de encadeamentos for criado no encadeamento da interface do usuário, a prioridade padrão do encadeamento será a mesma do encadeamento da interface do usuário, interrompendo assim os recursos usados ​​pelo encadeamento da interface do usuário.

Resumir


Este artigo apresenta em detalhes seis maneiras de implementar tarefas assíncronas no Android:

  1. Criado usando Tópico
  2. Use Thread + Looper + manipulador
  3. Usar AsyncTask
  4. Usar HandlerThread
  5. Usar IntentService
  6. Use um pool de threads para lidar com tarefas assíncronas

Ao mesmo tempo, também analisamos os cenários de uso de cada método e suas vantagens e desvantagens.


**PS: Para conteúdo mais emocionante, consulte --> "Desenvolvimento Android"
**PS: Para conteúdo mais interessante, consulte --> "Desenvolvimento Android"
**PS: Para conteúdo mais interessante, consulte --> "Desenvolvimento Android"


---------------------
Autor: Tio Bu
Fonte: CSDN
Original: https://blog.csdn.net/u011578734/article/details/110523825Declaração
de direitos autorais: Esta artigo é o artigo original do autor, anexe o link da postagem do blog para reimpressão!
Análise de conteúdo Por: CSDN, CNBLOG postagem no blog plug-in de reimpressão com um clique

Acho que você gosta

Origin blog.csdn.net/xiaowang_lj/article/details/131893248
Recomendado
Clasificación