Android
Kotlin
Fragment
coroutine

Measure multiple Fragment/View sizes with Kotlin coroutines

In a complex layout in Android, we need the size of multiple fragments/views. However, in a dynamic layout, these sizes may be changing frequently, and thus we must measure them when they are required.

This measurement cannot always be calculated immediately. For example, if a fragment view has just been created, getLeft()/getTop() etc. will return 0 because the view has no intrinsic size yet. We must therefore post a runnable, or assign a layoutListener, with a callback that returns the fragment size once it is known.

If we require the size of multiple fragments/views, our calling function must wait for all sizes to be returned before it can continue. In Kotlin, coroutines are a useful method of doing this.

This is our calling function, which waits for the result of multiple height measurements. It will return a list of heights in a completion handler.

override fun updateHeights(completion: (List<Int>) -> Unit)  {
    val job = launch {

        // "fragments" is a predefined list of CustomFragment type
        val deferred = fragments.map { fragment ->
            async(CommonPool) { fragment.computeHeight() }
        }
        completion(deferred.map { it.await() })
    }
}

This is our customFragment with a suspend function and continuation return value

class CustomFragment: Fragment {

    open suspend fun computeHeight() : Int = suspendCoroutine { continuation ->

        //call your measuring method with a callback that returns the result
        this.measureHeight({ size ->
            continuation.resume(size.height)
        })          
    }
}