Sobes.tech
Junior

Jak spustit kód v paralelním (ne hlavním) vlákně?

sobes.tech AI

Odpověď od AI

Pro paralelní provádění kódu v Androidu se používají různé mechanismy, které zabraňují blokování hlavního (UI) vlákna a zachovávají odezvu aplikace.

Standardní prostředky Androidu:

  1. Thread: Základní třída pro vytváření nového vlákna.

    new Thread(new Runnable() {
        @Override
        public void run() {
            // Kód pro provedení v paralelním vlákně
        }
    }).start();
    

    Nevýhoda: Ruční správa vláken může vést k problémům s životním cyklem a únikům paměti.

  2. AsyncTask (zastaralé): Zjednodušuje práci s paralelními vlákny a interakci s UI vláknem.

    private static class MyAsyncTask extends AsyncTask<Void, Void, Void> {
        @Override
        protected Void doInBackground(Void... params) {
            // Kód pro provedení na pozadí
            return null;
        }
    
        @Override
        protected void onPostExecute(Void result) {
            // Práce s UI vláknem po dokončení doInBackground
        }
    }
    // Použití: new MyAsyncTask().execute();
    

    Nevýhody: Zastaralé, má omezení a složitosti při správě životního cyklu.

  3. Handler a Looper: Umožňují vytvářet vlákna s cykly zpracování zpráv.

    HandlerThread handlerThread = new HandlerThread("MyWorkerThread");
    handlerThread.start();
    Handler handler = new Handler(handlerThread.getLooper());
    handler.post(new Runnable() {
        @Override
        public void run() {
            // Kód pro provedení ve vlákně s Looperem
        }
    });
    

    Výhoda: Vhodné pro opakující se úkoly nebo zpracování asynchronních událostí v samostatném vlákně.

  4. ExecutorService / ThreadPoolExecutor: Poskytují pooly vláken, což je efektivnější než vytváření nového Thread pro každý úkol.

    ExecutorService executor = Executors.newSingleThreadExecutor(); // Nebo newCachedThreadPool(), newFixedThreadPool(N)
    executor.execute(new Runnable() {
        @Override
        public void run() {
            // Kód pro provedení ve vlákně z poolu
        }
    });
    // Nezapomeňte zavolat executor.shutdown() při ukončení
    

    Výhody: Řídí vytváření a znovupoužití vláken, snižují režii.

Moderní přístupy:

  1. Kotlin Coroutines: Lehká vlákna, která nabízejí jednodušší a čitelnější způsob asynchronního programování.

    import kotlinx.coroutines.*
    
    // Spuštění korutiny v poolu vláken (analogicky s pozadím)
    GlobalScope.launch(Dispatchers.Default) {
        // Kód pro provedení na pozadí
    }
    
    // Spuštění korutiny pro IO operace
    GlobalScope.launch(Dispatchers.IO) {
        // Kód pro provádění IO operací (síť, soubory atd.)
    }
    
    // Přepnutí na UI vlákno pro aktualizaci uživatelského rozhraní
    GlobalScope.launch(Dispatchers.Default) {
        // Výpočty na pozadí
        withContext(Dispatchers.Main) {
            // Aktualizace UI
        }
    }
    

    Výhody: Zlepšená čitelnost kódu, efektivnější využití zdrojů, snadná správa zrušení úkolů, strukturovaná konkurence.

  2. RxJava / RxKotlin: Reaktivní programování založené na pozorovatelných datových tocích.

    import io.reactivex.rxjava3.core.Observable;
    import io.reactivex.rxjava3.schedulers.Schedulers;
    
    Observable.just("Nějaký výsledek")
        .subscribeOn(Schedulers.io()) // Provést na IO vlákně
        .observeOn(AndroidSchedulers.mainThread()) // Pozorovat na UI vlákně
        .subscribe(/* Zpracování výsledku */);
    

    Výhody: Výkonný nástroj pro práci s asynchronními událostmi a transformaci dat, ale s vyšší prahovou hodnotou vstupu.

Knihovna WorkManager:

  1. WorkManager: Doporučená komponenta z Architecture Components pro garantované provádění pozadí úkolů, i když je aplikace uzavřena nebo zařízení restartováno.
    import androidx.work.*
    import java.util.concurrent.TimeUnit
    
    class MyWorker: Worker(appContext, workerParams) {
        override fun doWork(): Result {
            // Kód pro provedení úkolu na pozadí
            return Result.success() // nebo Result.failure(), Result.retry()
        }
    }
    
    // Vytvoření požadavku na provedení úkolu
    val workRequest = OneTimeWorkRequestBuilder<MyWorker>()
        .setConstraints(Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED).build()) // Volitelné omezení
        .build()
    
    // Zařazení úkolu do fronty
    WorkManager.getInstance(context).enqueue(workRequest)
    
    Výhody: Garantované provedení, podpora omezení (typ sítě, nabíjení), správa zrušení, odložené provedení a opakování.

Výběr konkrétní metody závisí na typu úkolu, jeho životním cyklu a požadavcích na spolehlivost. Pro většinu moderních Android aplikací se doporučuje používat Kotlin Coroutines nebo WorkManager.