kosi-libs / Kodein

Painless Kotlin Dependency Injection
https://kosi-libs.org/kodein
MIT License
3.19k stars 174 forks source link

Composable #417

Closed dongzhaosheng73 closed 1 year ago

dongzhaosheng73 commented 2 years ago
class MainActivity : ComponentActivity(), DIAware { 
  override val di by closestDI(AppEntry.instance)

  @Preview(showBackground = true)
  @Composable
  fun DefaultPreview() {
    withDI(di = androidContextDI()) {
        Greeting("Android")
    }
  }
}

Using previews when the app is not initialized will report that DI is not initialized. What should I do in this case?

error: java.lang.IllegalStateException: Trying to find closest DI, but no DI container was found at all. Your Application should be DIAware.
romainbsl commented 1 year ago

Obviously you cannot access the Application context has it is not initialized from the preview point of view. In that case you could declare your DI as an internal variable like:

class KodeinSampleApp : Application(), DIAware {
    override val di: DI = internalDI
}

internal val internalDI: DI = DI {
    bindConstant("AUTHOR") { "Romain" }
}

Then you could use it in previews:

@Preview(showBackground = true)
@Composable
fun DefaultPreview() {
    KodeinSampleTheme {
        withDI(di = internalDI) {
            val author: String by rememberInstance("AUTHOR")
            Greeting(author.uppercase())
        }
    }
}
GSculerlor commented 1 year ago

sorry for necroposting/bumping this closed issue, but is there any way to make the preview work without declaring the DI as a variable? or is that the only way to make previewing Composable function with injected instance works?

romainbsl commented 1 year ago

You can, as suggested in my last post.

Here is another example


class TestApplication : Application(), DIAware {
    override val di: DI = DI.lazy {
        import(androidXModule(this@TestApplication))
        bindSingleton<Bar> { BarImpl() }
    }
}

interface Bar {
    val foo: String
}
class BarImpl : Bar {
    override val foo: String = "Romain for prod"
}

@Composable
fun TestPrev() {
    val bar by rememberInstance<Bar>()
    Text(bar.foo)
}

@Preview
@Composable
fun ShowPrev() {
    withDI(DI {
        bindSingleton { object : Bar {
            override val foo: String = "Romain from preview"
        } }
    }) {
        TestPrev()
    }
}

Here is a screenshot to demonstrate the preview:

Screenshot 2023-02-20 at 15 25 39