Sobes.tech
Junior

Como executar código numa thread paralela (não principal)?

sobes.tech IA

Resposta da IA

Para a execução paralela de código no Android, utilizam-se diversos mecanismos que permitem não bloquear o thread principal (UI) e manter a capacidade de resposta da aplicação.

Meios integrados do Android:

  1. Thread: Classe base para criar uma nova thread.

    new Thread(new Runnable() {
        @Override
        public void run() {
            // Código para executar na thread paralela
        }
    }).start();
    

    Desvantagem: A gestão manual de threads pode causar problemas com o ciclo de vida e fugas de memória.

  2. AsyncTask (Obsoleto): Facilitava o trabalho com threads paralelos e interação com a thread UI.

    private static class MyAsyncTask extends AsyncTask<Void, Void, Void> {
        @Override
        protected Void doInBackground(Void... params) {
            // Código para executar em segundo plano
            return null;
        }
    
        @Override
        protected void onPostExecute(Void result) {
            // Trabalho com a thread UI após doInBackground
        }
    }
    // Uso: new MyAsyncTask().execute();
    

    Desvantagens: Obsoleto, com limitações e dificuldades na gestão do ciclo de vida.

  3. Handler e Looper: Permitem criar threads com loops de processamento de mensagens.

    HandlerThread handlerThread = new HandlerThread("MyWorkerThread");
    handlerThread.start();
    Handler handler = new Handler(handlerThread.getLooper());
    handler.post(new Runnable() {
        @Override
        public void run() {
            // Código para executar na thread com Looper
        }
    });
    

    Vantagem: Útil para tarefas repetitivas ou gestão de eventos assíncronos em uma thread separada.

  4. ExecutorService / ThreadPoolExecutor: Fornecem grupos de threads, mais eficientes do que criar um novo Thread para cada tarefa.

    ExecutorService executor = Executors.newSingleThreadExecutor(); // Ou newCachedThreadPool(), newFixedThreadPool(N)
    executor.execute(new Runnable() {
        @Override
        public void run() {
            // Código para executar em um thread do grupo
        }
    });
    // Não esquecer de chamar executor.shutdown() ao finalizar
    

    Vantagens: Gerenciam a criação e reutilização de threads, reduzindo custos.

Abordagens modernas:

  1. Kotlin Coroutines: Threads leves que oferecem uma forma mais simples e legível de programação assíncrona.

    import kotlinx.coroutines.*
    
    // Iniciar uma coroutine em um grupo de threads (semelhante a um thread de fundo)
    GlobalScope.launch(Dispatchers.Default) {
        // Código para executar em segundo plano
    }
    
    // Iniciar uma coroutine para operações de IO
    GlobalScope.launch(Dispatchers.IO) {
        // Código para operações de IO (rede, arquivos, etc.)
    }
    
    // Alternar para o thread UI para atualizar a interface
    GlobalScope.launch(Dispatchers.Default) {
        // Cálculos em segundo plano
        withContext(Dispatchers.Main) {
            // Atualizar UI
        }
    }
    

    Vantagens: Melhor legibilidade do código, uso eficiente de recursos, gestão simples de cancelamento de tarefas, concorrência estruturada.

  2. RxJava / RxKotlin: Programação reativa baseada em fluxos de dados observáveis.

    import io.reactivex.rxjava3.core.Observable;
    import io.reactivex.rxjava3.schedulers.Schedulers;
    
    Observable.just("Algum resultado")
        .subscribeOn(Schedulers.io()) // Executar no thread IO
        .observeOn(AndroidSchedulers.mainThread()) // Observar no thread UI
        .subscribe(/* Processar resultado */);
    

    Vantagens: Ferramenta poderosa para eventos assíncronos e transformação de dados, mas com uma curva de aprendizagem mais elevada.

Biblioteca WorkManager:

  1. WorkManager: Componente recomendado do Architecture Components para garantir a execução confiável de tarefas em segundo plano, mesmo que a aplicação seja fechada ou o dispositivo seja reiniciado.
    import androidx.work.*
    import java.util.concurrent.TimeUnit
    
    class MyWorker(appContext: Context, workerParams: WorkerParameters): Worker(appContext, workerParams) {
        override fun doWork(): Result {
            // Código para executar a tarefa em segundo plano
            return Result.success() // Ou Result.failure(), Result.retry()
        }
    }
    
    // Criar uma solicitação para executar a tarefa
    val workRequest = OneTimeWorkRequestBuilder<MyWorker>()
        .setConstraints(Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED).build()) // Restrições opcionais
        .build()
    
    // Enfileirar a tarefa
    WorkManager.getInstance(context).enqueue(workRequest)
    
    Vantagens: Execução garantida, suporte a restrições (tipo de rede, bateria), gerenciamento de cancelamentos, execuções adiadas e repetições.

A escolha do método específico para executar código em um thread paralelo depende do tipo de tarefa, seu ciclo de vida e os requisitos de confiabilidade. Para a maioria das aplicações Android modernas, recomenda-se usar Kotlin Coroutines ou WorkManager.