Sobes.tech
Junior

How to execute code in a parallel (non-main) thread?

sobes.tech AI

Answer from AI

For parallel code execution in Android, various mechanisms are used that prevent blocking the main (UI) thread and maintain app responsiveness.

Android's built-in tools:

  1. Thread: Basic class for creating a new thread.

    new Thread(new Runnable() {
        @Override
        public void run() {
            // Code to execute in parallel thread
        }
    }).start();
    

    Disadvantage: Manual thread management can lead to lifecycle issues and memory leaks.

  2. AsyncTask (Deprecated): Simplified work with parallel threads and UI thread interaction.

    private static class MyAsyncTask extends AsyncTask<Void, Void, Void> {
        @Override
        protected Void doInBackground(Void... params) {
            // Code to run in background thread
            return null;
        }
    
        @Override
        protected void onPostExecute(Void result) {
            // Work with UI thread after doInBackground
        }
    }
    // Usage: new MyAsyncTask().execute();
    

    Downsides: Deprecated, has limitations and management complexities.

  3. Handler and Looper: Allow creating threads with message processing loops.

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

    Advantage: Convenient for repeated tasks or handling asynchronous events in a separate thread.

  4. ExecutorService / ThreadPoolExecutor: Provide thread pools, more efficient than creating a new Thread for each task.

    ExecutorService executor = Executors.newSingleThreadExecutor(); // Or newCachedThreadPool(), newFixedThreadPool(N)
    executor.execute(new Runnable() {
        @Override
        public void run() {
            // Code to run in pool thread
        }
    });
    // Remember to call executor.shutdown() when done
    

    Pros: Manage thread creation and reuse, reduce overhead.

Modern approaches:

  1. Kotlin Coroutines: Lightweight threads providing a simpler and more readable way of asynchronous programming.

    import kotlinx.coroutines.*
    
    // Launch a coroutine in a thread pool (background thread)
    GlobalScope.launch(Dispatchers.Default) {
        // Code to run in background thread
    }
    
    // Launch a coroutine for IO operations
    GlobalScope.launch(Dispatchers.IO) {
        // Code for IO operations (network, files, etc.)
    }
    
    // Switch to UI thread for UI updates
    GlobalScope.launch(Dispatchers.Default) {
        // Background computations
        withContext(Dispatchers.Main) {
            // UI update
        }
    }
    

    Benefits: Improved code readability, more efficient resource use, easy task cancellation, structured concurrency.

  2. RxJava / RxKotlin: Reactive programming based on observable data streams.

    import io.reactivex.rxjava3.core.Observable;
    import io.reactivex.rxjava3.schedulers.Schedulers;
    
    Observable.just("Some result")
        .subscribeOn(Schedulers.io()) // Execute in IO thread
        .observeOn(AndroidSchedulers.mainThread()) // Observe in UI thread
        .subscribe(/* Handle result */);
    

    Advantages: Powerful tool for asynchronous event handling and data transformation, but has a higher learning curve.

WorkManager library:

  1. WorkManager: Recommended Architecture Component for guaranteed background task execution, even if the app is closed or device is rebooted.
    import androidx.work.*
    import java.util.concurrent.TimeUnit
    
    class MyWorker: Worker(appContext, workerParams) {
        override fun doWork(): Result {
            // Code to perform background task
            return Result.success() // Or Result.failure(), Result.retry()
        }
    }
    
    // Create a work request
    val workRequest = OneTimeWorkRequestBuilder<MyWorker>()
        .setConstraints(Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED).build()) // Optional constraints
        .build()
    
    // Enqueue the task
    WorkManager.getInstance(context).enqueue(workRequest)
    
    Advantages: Guaranteed execution, support for constraints (network type, battery), cancellation management, deferred execution, retries.

The choice of method depends on the task type, lifecycle, and reliability requirements. For most modern Android apps, Kotlin Coroutines or WorkManager are recommended.

How to execute code in a parallel (non-main) thread… - sobes.tech