Sobes.tech
Junior

Kako izvršiti kod u paralelnom (ne glavnom) thread-u?

sobes.tech АИ

Одговор од АИ

Za paralelno izvršavanje koda u Android-u koriste se različiti mehanizmi koji omogućavaju da ne blokirate glavni (UI) tok i da sačuvate odzivnost aplikacije.

Standardni alati Android-a:

  1. Thread: Osnovna klasa za kreiranje novog toka.

    new Thread(new Runnable() {
        @Override
        public void run() {
            // Kod za izvršenje u paralelnom toku
        }
    }).start();
    

    Nedostatak: Ručno upravljanje tokovima može dovesti do problema sa životnim ciklusom i curenja memorije.

  2. AsyncTask (zastareo): Olakšavao je rad sa paralelnim tokovima i interakciju sa UI tokom.

    private static class MyAsyncTask extends AsyncTask<Void, Void, Void> {
        @Override
        protected Void doInBackground(Void... params) {
            // Kod za izvršenje u pozadinskom toku
            return null;
        }
    
        @Override
        protected void onPostExecute(Void result) {
            // Rad sa UI tokom nakon završetka doInBackground
        }
    }
    // Korišćenje: new MyAsyncTask().execute();
    

    Nedostaci: Zastareo je, ima ograničenja i složenosti u upravljanju životnim ciklusom.

  3. Handler i Looper: Omogućavaju kreiranje tokova sa petljama za obradu poruka.

    HandlerThread handlerThread = new HandlerThread("MyWorkerThread");
    handlerThread.start();
    Handler handler = new Handler(handlerThread.getLooper());
    handler.post(new Runnable() {
        @Override
        public void run() {
            // Kod za izvršenje u toku sa Looper-om
        }
    });
    

    Prednost: Pogodno za izvršavanje ponovljenih zadataka ili obrade asinhronih događaja u posebnom toku.

  4. ExecutorService / ThreadPoolExecutor: Obezbeđuju poolove tokova, što je efikasnije nego kreiranje novog Thread za svaku zadatak.

    ExecutorService executor = Executors.newSingleThreadExecutor(); // Ili newCachedThreadPool(), newFixedThreadPool(N)
    executor.execute(new Runnable() {
        @Override
        public void run() {
            // Kod za izvršenje u toku iz pool-a
        }
    });
    // Ne zaboravite da pozovete executor.shutdown() pri završetku
    

    Prednosti: Upravljaju kreiranjem i ponovnim korišćenjem tokova, smanjuju troškove.

Savremeni pristupi:

  1. Kotlin Coroutines: Laki tokovi, koji pružaju jednostavniji i čitljiviji način asinhronog programiranja.

    import kotlinx.coroutines.*
    
    // Pokretanje korutine u poolu tokova (analog pozadinskog toka)
    GlobalScope.launch(Dispatchers.Default) {
        // Kod za izvršenje u pozadinskom toku
    }
    
    // Pokretanje korutine za rad sa IO operacijama
    GlobalScope.launch(Dispatchers.IO) {
        // Kod za izvršenje IO operacija (rad sa mrežom, fajlovima itd.)
    }
    
    // Prebacivanje na UI tok za ažuriranje korisničkog interfejsa
    GlobalScope.launch(Dispatchers.Default) {
        // Pozadinske kalkulacije
        withContext(Dispatchers.Main) {
            // Ažuriranje UI
        }
    }
    

    Prednosti: Poboljšava čitljivost koda, efikasnije korišćenje resursa, jednostavno upravljanje otkazivanjem zadataka, strukturirana konkurentnost.

  2. RxJava / RxKotlin: Reaktivno programiranje zasnovano na posmatranim tokovima podataka.

    import io.reactivex.rxjava3.core.Observable;
    import io.reactivex.rxjava3.schedulers.Schedulers;
    
    Observable.just("Neki rezultat")
        .subscribeOn(Schedulers.io()) // Izvršiti u IO toku
        .observeOn(AndroidSchedulers.mainThread()) // Posmatrati u UI toku
        .subscribe(/* Obrada rezultata */);
    

    Prednosti: Moćan alat za rad sa asinhronim događajima i transformaciju podataka, ali ima viši prag ulaska.

Biblioteka WorkManager:

  1. WorkManager: Preporučeni komponent iz Architecture Components za garantovano izvršenje pozadinskih zadataka, čak i ako je aplikacija zatvorena ili uređaj restartovan.
    import androidx.work.*
    import java.util.concurrent.TimeUnit
    
    class MyWorker: Worker(appContext, workerParams) {
        override fun doWork(): Result {
            // Kod za izvršenje zadatka u pozadinskom toku
            return Result.success() // Ili Result.failure(), Result.retry()
        }
    }
    
    // Kreiranje zahteva za izvršenje zadatka
    val workRequest = OneTimeWorkRequestBuilder<MyWorker>()
        .setConstraints(Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED).build()) // Opcionalni uslovi
        .build()
    
    // Postavljanje zadatka u red
    WorkManager.getInstance(context).enqueue(workRequest)
    
    Prednosti: Garantovano izvršenje, podrška ograničenjima (tip mreže, punjenje baterije), upravljanje otkazivanjem, odloženo izvršenje i ponovljeni zadaci.

Izbor konkretne metode izvršenja koda u paralelnom toku zavisi od tipa zadatka, njegovog životnog ciklusa i zahteva za pouzdanošću izvršenja. Za većinu savremenih Android aplikacija preporučuje se korišćenje Kotlin Coroutines ili WorkManager.