Sobes.tech
Junior

Ako spustiť kód v paralelnom (ne hlavném) vlákne?

sobes.tech AI

Odpoveď od AI

Pre paralelného vykonávania kódu v Androide sa používajú rôzne mechanizmy, ktoré umožňujú neblokovať hlavný (UI) vlákno a zachovať odozvu aplikácie.

Štandardné prostriedky Androidu:

  1. Thread: Základná trieda na vytváranie nového vlákna.

    new Thread(new Runnable() {
        @Override
        public void run() {
            // Kód na vykonanie v paralelnom vlákne
        }
    }).start();
    

    Nevýhoda: Ručné riadenie vlákien môže viesť k problémom s životným cyklom a únikom pamäti.

  2. AsyncTask (zastaralé): Uľahčovalo prácu s paralelnými vláknami a interakciu s UI vláknom.

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

    Nevýhody: Zastaralé, má obmedzenia a ťažkosti pri riadení životného cyklu.

  3. Handler a Looper: Umožňujú vytváranie vlákien s cyklami na spracovanie správ.

    HandlerThread handlerThread = new HandlerThread("MyWorkerThread");
    handlerThread.start();
    Handler handler = new Handler(handlerThread.getLooper());
    handler.post(new Runnable() {
        @Override
        public void run() {
            // Kód na vykonanie v vlákne s Looperom
        }
    });
    

    Výhoda: Vhodné na vykonávanie opakujúcich sa úloh alebo spracovanie asynchrónnych udalostí v samostatnom vlákne.

  4. ExecutorService / ThreadPoolExecutor: Poskytujú pooly vlákien, čo je efektívnejšie, než vytváranie nového Thread pre každú úlohu.

    ExecutorService executor = Executors.newSingleThreadExecutor(); // Alebo newCachedThreadPool(), newFixedThreadPool(N)
    executor.execute(new Runnable() {
        @Override
        public void run() {
            // Kód na vykonanie v vlákne z poolu
        }
    });
    // Zabudnite zavolať executor.shutdown() pri ukončení
    

    Výhody: Riadi vytváranie a opätovné používanie vlákien, znižujú náklady.

Súčasné prístupy:

  1. Kotlin Coroutines: Ľahké vlákna, ktoré poskytujú jednoduchší a čitateľnejší spôsob asynchrónneho programovania.

    import kotlinx.coroutines.*
    
    // Spustenie korutiny v poolu vlákien (analóg pozadia)
    GlobalScope.launch(Dispatchers.Default) {
        // Kód na vykonanie na pozadí
    }
    
    // Spustenie korutiny na prácu s IO operáciami
    GlobalScope.launch(Dispatchers.IO) {
        // Kód na vykonanie IO operácií (práca so sieťou, súbormi a pod.)
    }
    
    // Prepnúť na UI vlákno na aktualizáciu používateľského rozhrania
    GlobalScope.launch(Dispatchers.Default) {
        // Pozadie výpočty
        withContext(Dispatchers.Main) {
            // Aktualizácia UI
        }
    }
    

    Výhody: Zlepšuje čitateľnosť kódu, efektívnejšie využitie zdrojov, jednoduché riadenie zrušenia úloh, štruktúrovaná konkurencia.

  2. RxJava / RxKotlin: Reaktívne programovanie založené na pozorovateľných tokoch dát.

    import io.reactivex.rxjava3.core.Observable;
    import io.reactivex.rxjava3.schedulers.Schedulers;
    
    Observable.just("Niekdejší výsledok")
        .subscribeOn(Schedulers.io()) // Vykonať v IO vlákne
        .observeOn(AndroidSchedulers.mainThread()) // Pozorovať v UI vlákne
        .subscribe(/* Spracovanie výsledku */);
    

    Výhody: Silný nástroj na prácu s asynchrónnymi udalosťami a transformáciu dát, ale má vyššiu prahovú hranicu vstupu.

Knižnica WorkManager:

  1. WorkManager: Odporúčaný komponent z Architecture Components na garantované vykonanie pozadinských úloh, aj keď je aplikácia zatvorená alebo zariadenie reštartované.
    import androidx.work.*
    import java.util.concurrent.TimeUnit
    
    class MyWorker: Worker(appContext, workerParams) {
        override fun doWork(): Result {
            // Kód na vykonanie úlohy v pozadí
            return Result.success() // Alebo Result.failure(), Result.retry()
        }
    }
    
    // Vytvorenie požiadavky na vykonanie úlohy
    val workRequest = OneTimeWorkRequestBuilder<MyWorker>()
        .setConstraints(Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED).build()) // Voliteľné obmedzenia
        .build()
    
    // Postavenie úlohy do fronty
    WorkManager.getInstance(context).enqueue(workRequest)
    
    Výhody: Garantované vykonanie, podpora obmedzení (typ siete, nabíjanie batérie), riadenie zrušenia, odložené vykonanie a opakovania.

Výber konkrétnej metódy na vykonanie kódu v paralelnom vlákne závisí od typu úlohy, jej životného cyklu a požiadaviek na spoľahlivosť vykonania. Pre väčšinu moderných Android aplikácií sa odporúča použiť Kotlin Coroutines alebo WorkManager.