Sobes.tech
Junior

Kaip vykdyti kodą paraleliniame (ne pagrindiniame) sraute?

sobes.tech AI

Atsakymas iš AI

Android naudoja įvairius mechanizmus, leidžiančius vykdyti kodą lygiagrečiai, nesukeliant pagrindinio (UI) srauto blokavimo ir išlaikant programėlės reakciją.

Android standartinės priemonės:

  1. Thread: Pagrindinė naujo srauto kūrimo klasė.

    new Thread(new Runnable() {
        @Override
        public void run() {
            // Kodas, vykdomas lygiagrečiame sraute
        }
    }).start();
    

    Trūkumas: Rankinis srautų valdymas gali sukelti gyvenimo ciklo problemų ir atminties nutekėjimą.

  2. AsyncTask (pasenusi): Supaprastino darbą su lygiagrečiais srautais ir sąveiką su UI srautu.

    private static class MyAsyncTask extends AsyncTask<Void, Void, Void> {
        @Override
        protected Void doInBackground(Void... params) {
            // Kodas, vykdomas fono sraute
            return null;
        }
    
        @Override
        protected void onPostExecute(Void result) {
            // Darbas su UI srautu po doInBackground pabaigos
        }
    }
    // Naudojimas: new MyAsyncTask().execute();
    

    Trūkumai: Pasenusi, turi apribojimų ir sudėtingumų gyvenimo ciklo valdyme.

  3. Handler ir Looper: Leidžia kurti srautus su žinučių apdorojimo ciklais.

    HandlerThread handlerThread = new HandlerThread("MyWorkerThread");
    handlerThread.start();
    Handler handler = new Handler(handlerThread.getLooper());
    handler.post(new Runnable() {
        @Override
        public void run() {
            // Kodas, vykdomas su Looper sraute
        }
    });
    

    Privalumas: Patogu vykdyti pasikartojančias užduotis arba apdoroti asinchroninius įvykius atskirame sraute.

  4. ExecutorService / ThreadPoolExecutor: Teikia srauto baseinus, kurie yra efektyvesni nei kurti naują Thread kiekvienai užduočiai.

    ExecutorService executor = Executors.newSingleThreadExecutor(); // Arba newCachedThreadPool(), newFixedThreadPool(N)
    executor.execute(new Runnable() {
        @Override
        public void run() {
            // Kodas, vykdomas iš srauto iš baseino
        }
    });
    // Nepamiršti išjungti executor.shutdown() kai baigsite
    

    Pranašumai: Valdo srautų kūrimą ir pakartotinį naudojimą, mažina išlaidas.

Šiuolaikiniai metodai:

  1. Kotlin Coroutines: Lengvi srautai, siūlantys paprastesnį ir skaitomesnį būdą asinchroniniam programavimui.

    import kotlinx.coroutines.*
    
    // Korutinos paleidimas srauto baseine (analogas foniniam srautui)
    GlobalScope.launch(Dispatchers.Default) {
        // Kodas, vykdomas foniniame sraute
    }
    
    // Korutinos paleidimas darbui su IO operacijomis
    GlobalScope.launch(Dispatchers.IO) {
        // Kodas, vykdomas su IO operacijomis (tinklas, failai ir kt.)
    }
    
    // Perjungimas į UI srautą atnaujinti naudotojo sąsają
    GlobalScope.launch(Dispatchers.Default) {
        // Fono skaičiavimai
        withContext(Dispatchers.Main) {
            // UI atnaujinimas
        }
    }
    

    Pranašumai: Pagerinta kodo skaitomumas, efektyvesnis išteklių naudojimas, paprastas užduočių atšaukimas, struktūruotas konkurencingumas.

  2. RxJava / RxKotlin: Reaktyvus programavimas, pagrįstas stebimais duomenų srautais.

    import io.reactivex.rxjava3.core.Observable;
    import io.reactivex.rxjava3.schedulers.Schedulers;
    
    Observable.just("Tam tikras rezultatas")
        .subscribeOn(Schedulers.io()) // Vykdyti IO sraute
        .observeOn(AndroidSchedulers.mainThread()) // Stebėti UI sraute
        .subscribe(/* Rezultato apdorojimas */);
    

    Pranašumai: Galingas įrankis asinchroniniams įvykiams ir duomenų transformacijai, bet turi aukštesnį įsisavinimo barjerą.

WorkManager biblioteka:

  1. WorkManager: Rekomenduojamas Architecture Components komponentas garantuotam foninių užduočių vykdymui, net jei programa uždaryta arba įrenginys perkrautas.
    import androidx.work.*
    import java.util.concurrent.TimeUnit
    
    class MyWorker: Worker(appContext, workerParams) {
        override fun doWork(): Result {
            // Kodas, vykdomas foninėje užduotyje
            return Result.success() // Ar Result.failure(), Result.retry()
        }
    }
    
    // Užklausos sukūrimas užduočiai vykdyti
    val workRequest = OneTimeWorkRequestBuilder<MyWorker>()
        .setConstraints(Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED).build()) // Pasirinktiniai apribojimai
        .build()
    
    // Užduoties iškėlimas į eilę
    WorkManager.getInstance(context).enqueue(workRequest)
    
    Pranašumai: Garantija, kad užduotis bus įvykdyta, palaiko apribojimus (tinklo tipas, akumuliatoriaus įkrova), valdymas atšaukimui, atidėtas vykdymas ir pakartojimai.

Konkretaus metodo pasirinkimas priklauso nuo užduoties tipo, jos gyvenimo ciklo ir patikimumo reikalavimų. Dauguma šiuolaikinių Android programėlių rekomenduoja naudoti Kotlin Coroutines arba WorkManager.