Sobes.tech
Junior

Hoe voer je code uit in een parallel (niet-hoofd) thread?

sobes.tech AI

Antwoord van AI

Voor het parallel uitvoeren van code in Android worden verschillende mechanismen gebruikt die voorkomen dat de hoofd- (UI) thread wordt geblokkeerd en de responsiviteit van de app behouden blijft.

Standaard Android-middelen:

  1. Thread: Basisklasse voor het maken van een nieuwe thread.

    new Thread(new Runnable() {
        @Override
        public void run() {
            // Code voor uitvoering in parallelle thread
        }
    }).start();
    

    Nadelen: Handmatig beheer van threads kan leiden tot problemen met de levenscyclus en geheugenlekken.

  2. AsyncTask (Verouderd): Vereenvoudigde omgang met parallelle threads en interactie met de UI-thread.

    private static class MyAsyncTask extends AsyncTask<Void, Void, Void> {
        @Override
        protected Void doInBackground(Void... params) {
            // Code voor uitvoering op de achtergrond
            return null;
        }
    
        @Override
        protected void onPostExecute(Void result) {
            // Werken met UI-thread na voltooiing van doInBackground
        }
    }
    // Gebruik: new MyAsyncTask().execute();
    

    Nadelen: Verouderd, heeft beperkingen en moeilijkheden bij het beheren van de levenscyclus.

  3. Handler en Looper: Stellen het maken van threads met berichtverwerkingslussen mogelijk.

    HandlerThread handlerThread = new HandlerThread("MyWorkerThread");
    handlerThread.start();
    Handler handler = new Handler(handlerThread.getLooper());
    handler.post(new Runnable() {
        @Override
        public void run() {
            // Code voor uitvoering in thread met Looper
        }
    });
    

    Voordeel: Handig voor het uitvoeren van herhaalde taken of het verwerken van asynchrone gebeurtenissen in een aparte thread.

  4. ExecutorService / ThreadPoolExecutor: Bieden thread-pools, wat efficiënter is dan het maken van een nieuwe Thread voor elke taak.

    ExecutorService executor = Executors.newSingleThreadExecutor(); // Of newCachedThreadPool(), newFixedThreadPool(N)
    executor.execute(new Runnable() {
        @Override
        public void run() {
            // Code voor uitvoering in pool-oqim
        }
    });
    // Vergeet niet executor.shutdown() aan te roepen bij voltooiing
    

    Voordelen: Beheren het maken en hergebruik van threads, verminderen overhead.

Moderne benaderingen:

  1. Kotlin Coroutines: Lichtgewicht threads die een eenvoudigere en beter leesbare manier bieden voor asynchrone programmering.

    import kotlinx.coroutines.*
    
    // Start een coroutine in een threadpool (analogie met achtergrondthread)
    GlobalScope.launch(Dispatchers.Default) {
        // Code voor uitvoering op de achtergrond
    }
    
    // Start een coroutine voor IO-operaties
    GlobalScope.launch(Dispatchers.IO) {
        // Code voor uitvoeren van IO-operaties (netwerk, bestanden, etc.)
    }
    
    // Overschakelen naar UI-thread voor het bijwerken van de gebruikersinterface
    GlobalScope.launch(Dispatchers.Default) {
        // Achtergrondberekeningen
        withContext(Dispatchers.Main) {
            // UI bijwerken
        }
    }
    

    Voordelen: Verbeterde leesbaarheid van code, efficiënter gebruik van bronnen, eenvoudige taakannullatiebeheer, gestructureerde gelijktijdigheid.

  2. RxJava / RxKotlin: Reactieve programmering gebaseerd op observeerbare datastromen.

    import io.reactivex.rxjava3.core.Observable;
    import io.reactivex.rxjava3.schedulers.Schedulers;
    
    Observable.just("Een resultaat")
        .subscribeOn(Schedulers.io()) // Uitvoeren op IO-thread
        .observeOn(AndroidSchedulers.mainThread()) // Observer op UI-thread
        .subscribe(/* Resultaatverwerking */);
    

    Voordelen: Krachtig hulpmiddel voor het werken met asynchrone gebeurtenissen en datavervorming, maar met een hogere instapdrempel.

Bibliotheek WorkManager:

  1. WorkManager: Aanbevolen component van Architecture Components voor gegarandeerde uitvoering van achtergrondtaken, zelfs als de app is gesloten of het apparaat opnieuw is opgestart.
    import androidx.work.*
    import java.util.concurrent.TimeUnit
    
    class MyWorker: Worker(appContext, workerParams) {
        override fun doWork(): Result {
            // Code voor uitvoeren van taak op achtergrond
            return Result.success() // of Result.failure(), Result.retry()
        }
    }
    
    // Aanmaken van een taakverzoek
    val workRequest = OneTimeWorkRequestBuilder<MyWorker>()
        .setConstraints(Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED).build()) // Optionele beperkingen
        .build()
    
    // Taak in wachtrij plaatsen
    WorkManager.getInstance(context).enqueue(workRequest)
    
    Voordelen: Gegarandeerde uitvoering, ondersteuning voor beperkingen (netwerktype, batterijstatus), beheer van annulering, uitgestelde uitvoering en herhalingen.

De keuze voor een specifieke methode hangt af van het type taak, de levenscyclus en de betrouwbaarheidseisen. Voor de meeste moderne Android-apps worden Kotlin Coroutines of WorkManager aanbevolen.