Home > Software design >  Jetpack Compose doesn't respect Higher Order Classes
Jetpack Compose doesn't respect Higher Order Classes

Time:12-14

How to overcome / solve the next snippet to fulfill Jetpack Compose compiler (synthetic sample):

enum class UINavigator: @Composable () -> Unit {
    MAIN;

    private val nav: NavHostController = rememberNavController()

    override operator fun invoke() = ...
}

Error:

@Composable invocations can only happen from the context of a @Composable function

However, UINavigator already implements Higher Order Function.

Is it a bug or a restriction which doesn't cover in Documentation ?

CodePudding user response:

This error likely comes from two parts.

A) nav is defined as a property inside the class. This is instantiated when the class is created, which is not necessarily in a Composable Scope. Additionally, this is an enum class which means that it's instantiated statically (depending on the VM, could happen at launch or when first read).

B) The Compose compiler plugin adds some magic to functions so even if we add the @Composable annotation to the overridden function, there is a conflict introduced:

enter image description here

There are a couple of things you can try:

Option A: Define an operator without extending a function type:

enum class UINavigator {
    MAIN;

    @Composable operator fun invoke() {
        val nav: NavHostController = rememberNavController()
        // ...
    }
}

You can still use it as a function. Note that the nav property. If you want to share state across them all, you can either use a StateFlow or a Composition Local.

Option B: Using extension functions

enum class UINavigator {
    MAIN;
}

@Composable operator fun UINavigator.invoke() {
    val nav: NavHostController = rememberNavController()
    // ...
}

To all effects, the same as option A.

  • Related