Package 

Class ThreadingKt

    • Method Summary

      Modifier and Type Method Description
      final static <T extends Any> Result<T> runOnMainLooper(Function0<T> block) Executes the given block on the main (UI) thread and returns the result.
      final static <T extends Any> Result<T> runOn(Looper looper, Function0<T> block) Executes the given block on the specified looper's thread and returns the result.
      • Methods inherited from class java.lang.Object

        clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
    • Method Detail

      • runOnMainLooper

         final static <T extends Any> Result<T> runOnMainLooper(Function0<T> block)

        Executes the given block on the main (UI) thread and returns the result.

        This function provides thread-safe access to the main looper with proper synchronization:

        • If already on the main thread, executes block immediately

        • If on a different thread, posts to the main looper and blocks the caller until completion

        • Returns a Result that captures success values or exceptions from block

        This function is blocking for the calling thread when switching threads. It uses a CountDownLatch to wait for the main thread to complete execution before returning.

        If the main thread does not execute block within 5 seconds, this function throws IllegalStateException. This prevents indefinite blocking if the main thread is stuck.

        • Exceptions thrown by block are captured and returned as Result.failure

        • kotlin.coroutines.cancellation.CancellationException is rethrown to preserve coroutine cancellation semantics

        • If the main looper is not initialized, throws IllegalStateException

        • Updating UI components from background threads

        • Adding/removing lifecycle observers (requires main thread)

        • Accessing View properties that must be read on the main thread

        • Synchronizing with main thread state before proceeding

        // From a background thread, safely add a lifecycle observer
        runOnMainLooper {
            lifecycle.addObserver(observer)
        }.onFailure { error ->
            logger.e(error) { "Failed to add lifecycle observer" }
        }
        
        // Get a value from the UI thread
        val result = runOnMainLooper {
            view.width
        }.getOrNull()
        
        // Execute multiple UI operations atomically
        runOnMainLooper {
            textView.text = "Loading..."
            progressBar.visibility = View.VISIBLE
        }
        Parameters:
        block - the code to execute on the main thread
      • runOn

         final static <T extends Any> Result<T> runOn(Looper looper, Function0<T> block)

        Executes the given block on the specified looper's thread and returns the result.

        This is a generalized version of runOnMainLooper that works with any Looper:

        • If already on the target looper's thread, executes block immediately

        • If on a different thread, posts to the target looper and blocks the caller until completion

        • Returns a Result that captures success values or exceptions from block

        This function is blocking for the calling thread when switching threads. It uses a CountDownLatch to wait for the target looper's thread to complete execution before returning.

        If the target looper does not execute block within 5 seconds, this function throws IllegalStateException. This prevents indefinite blocking if the target thread is stuck or the looper is not running.

        • Exceptions thrown by block are captured and returned as Result.failure

        • kotlin.coroutines.cancellation.CancellationException is rethrown to preserve coroutine cancellation semantics

        • Executing code on a custom HandlerThread's looper

        • Synchronizing operations across multiple threads with known loopers

        • Testing thread-specific behavior with custom test loopers

        // Execute on a custom background thread
        val handlerThread = HandlerThread("worker").apply { start() }
        val workerLooper = handlerThread.looper
        
        runOn(workerLooper) {
            // This code runs on the worker thread
            performExpensiveOperation()
        }.onSuccess { result ->
            println("Operation completed with result: $result")
        }
        
        // Verify we're on the correct thread
        val isCorrectThread = runOn(targetLooper) {
            Looper.myLooper() == targetLooper
        }.getOrDefault(false)
        
        // Chain thread operations
        runOn(backgroundLooper) {
            val data = fetchData()
            runOnMainLooper {
                updateUI(data)
            }
        }
        • When already on the target looper's thread, there is minimal overhead (just a looper check)

        • When switching threads, the calling thread blocks until execution completes

        • Consider using coroutines with appropriate dispatchers for non-blocking alternatives

        Parameters:
        looper - the Looper on whose thread to execute block
        block - the code to execute on the looper's thread