Skip to content

Commit

Permalink
Merge branch '4.0.2' into patch-1
Browse files Browse the repository at this point in the history
  • Loading branch information
arnaudgiuliani authored Jan 16, 2025
2 parents 12c092b + 6329a4c commit a28242a
Show file tree
Hide file tree
Showing 47 changed files with 374 additions and 207 deletions.
4 changes: 2 additions & 2 deletions docs/reference/koin-android/start.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ By using Gradle packge `koin-androidx-startup`, we can use `KoinStartup` interfa
```kotlin
class MainApplication : Application(), KoinStartup {

override fun onKoinStartup(): KoinConfiguration = koinConfiguration {
override fun onKoinStartup(): KoinConfiguration = koinConfiguration {
androidContext(this@MainApplication)
modules(appModule)
}
Expand All @@ -90,7 +90,7 @@ class MainApplication : Application(), KoinStartup {
}
```

This replaces the `startKoin` function that is usally used in `onCreate`.
This replaces the `startKoin` function that is usally used in `onCreate`. The `koinConfiguration` function is returning a `KoinConfiguration` instance.

:::info
`KoinStartup` avoid blocking main thread at for startup time, and offers better performances.
Expand Down
58 changes: 38 additions & 20 deletions docs/reference/koin-compose/compose.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,58 +20,59 @@ for an Android/Multiplatform app, use the following packages:
- `koin-compose-viewmodel` - Compose ViewModel API
- `koin-compose-viewmodel-navigation` - Compose ViewModel API with Navigation API integration

## Starting Koin in a Compose App with KoinApplication
## Starting over an existing Koin context (Koin already started)

The function `KoinApplication` helps to create Koin application instance, as a Composable:
Some time the `startKoin` function is already used in the application, to start Koin in your application (like in Android main app class, the Application class). In that case you need to inform your Compose application about the current Koin context with `KoinContext` or `KoinAndroidContext`. Those functions reuse current Koin context and bind it to the Compose application.

```kotlin
@Composable
fun App() {
KoinApplication(application = {
modules(...)
}) {

// your screens here ...
// Set current Koin instance to Compose context
KoinContext() {

MyScreen()
}
}
```

The `KoinApplication` function will handle start & stop of your Koin context, regarding the cycle of the Compose context. This function start and stop a new Koin application context.

:::info
In an Android Application, the `KoinApplication` will handle any need to stop/restart Koin context regarding configuration changes or drop of Activities.
Difference between `KoinAndroidContext` and `KoinContext`:
- `KoinAndroidContext` is looking into current Android app context for Koin instance
- `KoinContext` is looking into current GlobalContext for Koin instances
:::

:::note
This replaces the use of the classic `startKoin` application function.
If you get some `ClosedScopeException` from a Composable, either use `KoinContext` on your Composable or ensure to have proper Koin start configuration [with Android context](/docs/reference/koin-android/start.md#from-your-application-class)
:::

## Starting over an existing Koin context
## Starting Koin with a Compose App - KoinApplication

Some time the `startKoin` function is already used in the application, to start Koin in your application (like in Android main app class, the Application class). In that case you need to inform your Compose application about the current Koin context with `KoinContext` or `KoinAndroidContext`. Those functions reuse current Koin context and bind it to the Compose application.
The function `KoinApplication` helps to create Koin application instance, as a Composable:

```kotlin
@Composable
fun App() {
// Set current Koin instance to Compose context
KoinContext() {

KoinApplication(application = {
modules(...)
}) {

// your screens here ...
MyScreen()
}
}
```

The `KoinApplication` function will handle start & stop of your Koin context, regarding the cycle of the Compose context. This function start and stop a new Koin application context.

:::info
Difference between `KoinAndroidContext` and `KoinContext`:
- `KoinAndroidContext` is looking into current Android app context for Koin instance
- `KoinContext` is looking into current GlobalContext for Koin instances
In an Android Application, the `KoinApplication` will handle any need to stop/restart Koin context regarding configuration changes or drop of Activities.
:::

:::note
If you get some `ClosedScopeException` from a Composable, either use `KoinContext` on your Composable or ensure to have proper Koin start configuration [with Android context](/docs/reference/koin-android/start.md#from-your-application-class)
This replaces the use of the classic `startKoin` application function.
:::


### Compose Preview with Koin

The `KoinApplication` function is interesting to start dedicated context for preview. This can be also used to help with Compose preview:
Expand Down Expand Up @@ -122,6 +123,23 @@ fun App(myService: MyService = koinInject()) {
}
```

### Injecting into a @Composable with Parameters

While you request a new dependency from Koin, you may need to inject parameters. To do this you can use `parameters` parameter of the `koinInject` function, with the `parametersOf()` function like this:

```kotlin
@Composable
fun App() {
val myService = koinInject<MyService>(parameters = parametersOf("a_string"))
}
```

:::info
You can use parameters with lambda injection like `koinInject<MyService>{ parametersOf("a_string") }`, but this can have a performance impact if your recomposing a lot around. This version with lambda needs to unwrap your parameters on call, to help avoid remembering your parameters.

From version 4.0.2 of Koin, koinInject(Qualifier,Scope,ParametersHolder) is introduced to let you use parameters in the most efficient way
:::

## ViewModel for @Composable

The same way you have access to classical single/factory instances, you gain access to the following Koin ViewModel API:
Expand Down
2 changes: 1 addition & 1 deletion docs/setup/koin.md
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ dependencies {
```

:::info
From now you can continue on Koin Tutorials to learn about using Koin: [Kotlin Multiplatform App Tutorial](/docs/quickstart/kmm)
From now you can continue on Koin Tutorials to learn about using Koin: [Kotlin Multiplatform App Tutorial](/docs/quickstart/kmp)
:::

### **Ktor**
Expand Down
2 changes: 1 addition & 1 deletion examples/androidx-samples/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ dependencies {
implementation "io.insert-koin:koin-core-coroutines"
implementation "io.insert-koin:koin-androidx-workmanager"
implementation "io.insert-koin:koin-androidx-navigation"
implementation "io.insert-koin:koin-androidx-startup"
// implementation "io.insert-koin:koin-androidx-startup"
testImplementation "io.insert-koin:koin-test-junit4"
testImplementation "io.insert-koin:koin-android-test"
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import org.koin.android.ext.koin.androidFileProperties
import org.koin.android.ext.koin.androidLogger
import org.koin.androidx.fragment.koin.fragmentFactory
import org.koin.androidx.workmanager.koin.workManagerFactory
import org.koin.androix.startup.KoinStartup
import org.koin.core.context.GlobalContext.startKoin
import org.koin.core.lazyModules
import org.koin.core.logger.Level
Expand All @@ -22,24 +21,15 @@ import org.koin.mp.KoinPlatform
import org.koin.sample.sandbox.di.allModules


class MainApplication : Application(), KoinStartup {
class MainApplication : Application() {

override fun onKoinStartup() = koinConfiguration {
androidLogger(Level.DEBUG)
androidContext(this@MainApplication)
androidFileProperties()
fragmentFactory()
workManagerFactory()
// lazyModules(allModules, dispatcher = IO)
modules(allModules)
}

// override fun onKoinStartup() : KoinAppDeclaration = {
// override fun onKoinStartup() = koinConfiguration {
// androidLogger(Level.DEBUG)
// androidContext(this@MainApplication)
// androidFileProperties()
// fragmentFactory()
// workManagerFactory()
//// lazyModules(allModules, dispatcher = IO)
// modules(allModules)
// }

Expand Down Expand Up @@ -68,20 +58,20 @@ class MainApplication : Application(), KoinStartup {

startTime = System.currentTimeMillis()

// startKoin {
// androidLogger(Level.DEBUG)
// androidContext(this@MainApplication)
// androidFileProperties()
// fragmentFactory()
// workManagerFactory()
//// lazyModules(allModules, dispatcher = IO)
// modules(allModules)
// }
startKoin {
androidLogger(Level.DEBUG)
androidContext(this@MainApplication)
androidFileProperties()
fragmentFactory()
workManagerFactory()
// lazyModules(allModules, dispatcher = IO)
modules(allModules)
}

//TODO Load/Unload Koin modules scenario cases
cancelPendingWorkManager(this)

KoinPlatform.getKoin().waitAllStartJobs()
// KoinPlatform.getKoin().waitAllStartJobs()
}
}

Expand Down
2 changes: 1 addition & 1 deletion examples/gradle/versions.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ ext {
// Kotlin
kotlin_version = '2.0.21'
// Koin Versions
koin_version = '4.0.1-RC2'
koin_version = '4.0.2-RC3'
koin_android_version = koin_version
koin_compose_version = koin_version

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ package org.koin.sample.androidx.compose
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.material.Button
import androidx.compose.material.Surface
import androidx.compose.material.Text
import androidx.compose.material.TextField
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
Expand All @@ -20,6 +22,7 @@ import org.koin.sample.androidx.compose.data.MySingle
import org.koin.sample.androidx.compose.di.secondModule
import org.koin.sample.androidx.compose.viewmodel.SSHViewModel
import org.koin.sample.androidx.compose.viewmodel.UserViewModel
import java.util.UUID


@Composable
Expand All @@ -43,6 +46,9 @@ fun App(userViewModel: UserViewModel = koinViewModel()) {
item {
ButtonForCreate("-X- Main") { created = !created }
}
item {
MyScreen()
}
}
} else {
Surface(modifier = Modifier.padding(8.dp)) {
Expand All @@ -52,6 +58,27 @@ fun App(userViewModel: UserViewModel = koinViewModel()) {

}

@Composable
fun MyScreen() {

var someValue by remember { mutableStateOf("initial") }
val myDependency = koinInject<MyFactory>(parameters = parametersOf(someValue))

SideEffect {
println("MyScreen 1")
}

Column {
Text(text = myDependency.id)
TextField(someValue, onValueChange = { someValue = it })
Button(onClick = {
if (someValue == "") someValue = "${UUID.randomUUID()}"
}) {
Text("Update")
}
}
}

@Composable
fun ViewModelComposable(
parentStatus: String = "- status -",
Expand All @@ -70,21 +97,6 @@ fun ViewModelComposable(
}
}

// Preview

//val fakeKoin = module {
// singleOf(::MySingle)
// factoryOf(::MyInnerFactory)
//}
//
//@Preview
//@Composable
//fun PreviewViewModelComposable() {
// KoinApplication(moduleList = { listOf(fakeKoin) }) {
// SingleComposable()
// }
//}


@Composable
fun SingleComposable(
Expand All @@ -105,7 +117,7 @@ fun SingleComposable(
@Composable
fun FactoryComposable(
parentStatus: String = "- status -",
myFactory: MyFactory = koinInject { parametersOf("stable_status") }
myFactory: MyFactory = koinInject(parameters = parametersOf("stable_status"))
) {
var created by remember { mutableStateOf(false) }
rememberKoinModules(modules = { listOf(secondModule) })
Expand All @@ -132,7 +144,7 @@ fun FactoryComposable(
//TODO Hold instance until recreate Composable
fun InnerFactoryComposable(
parentStatus: String,
myFactory: MyInnerFactory = koinInject { parametersOf("_stable_") }
myFactory: MyInnerFactory = koinInject(parameters = parametersOf("_stable_"))
) {
var created by remember { mutableStateOf(false) }
if (created) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ class MainApplication : Application() {

startKoin {
androidLogger(Level.DEBUG)
// printLogger(Level.DEBUG)
androidContext(this@MainApplication)
modules(appModule)
}
Expand Down
Loading

0 comments on commit a28242a

Please sign in to comment.