Skip to content

Commit f38a30f

Browse files
add UnboundKoinScope API + @KoinDelicateAPI
1 parent 0c1e17b commit f38a30f

File tree

2 files changed

+99
-1
lines changed

2 files changed

+99
-1
lines changed
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
/*
2+
* Copyright 2017-present the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.koin.compose.scope
17+
18+
import androidx.compose.runtime.Composable
19+
import androidx.compose.runtime.CompositionLocalProvider
20+
import org.koin.compose.ComposeContextWrapper
21+
import org.koin.compose.LocalKoinScopeContext
22+
import org.koin.core.annotation.KoinDelicateAPI
23+
import org.koin.core.annotation.KoinExperimentalAPI
24+
import org.koin.core.annotation.KoinInternalApi
25+
import org.koin.core.scope.Scope
26+
27+
/**
28+
* Safely provides an existing Koin scope to [LocalKoinScopeContext] without binding it to the Composable lifecycle.
29+
*
30+
* This function sets the given scope as the current [LocalKoinScopeContext] for the composable hierarchy,
31+
* allowing child composables to access it through Koin's injection APIs. The scope must already exist
32+
* and is provided directly.
33+
*
34+
* **Important**: This function does NOT manage the scope lifecycle. The scope is unbound from the
35+
* Composable and will not be automatically closed when the composable leaves composition. You must
36+
* manually close the scope when it's no longer needed to prevent memory leaks.
37+
*
38+
* Use this when you need to provide a scope that has a different lifecycle than the Composable,
39+
* such as scopes managed by external systems or shared across multiple composable trees.
40+
*
41+
* Example usage:
42+
* ```kotlin
43+
* @Composable
44+
* fun MyFeature(externalScope: Scope, onClose: () -> Unit) {
45+
* UnboundKoinScope(scope = externalScope) {
46+
* // Child composables can access the scope via LocalKoinScopeContext
47+
* val myService = koinInject<MyService>()
48+
*
49+
* // Remember to close the scope externally
50+
* DisposableEffect(Unit) {
51+
* onDispose { onClose() }
52+
* }
53+
* }
54+
* }
55+
* ```
56+
*
57+
* @param scope The existing Koin scope to provide to [LocalKoinScopeContext]
58+
* @param content The composable content that will have access to the scope via [LocalKoinScopeContext]
59+
*
60+
* @see rememberKoinScope for automatically lifecycle-managed scopes
61+
*/
62+
@OptIn(KoinInternalApi::class)
63+
@KoinDelicateAPI
64+
@KoinExperimentalAPI
65+
@Composable
66+
inline fun UnboundKoinScope(
67+
scope : Scope,
68+
noinline content: @Composable () -> Unit
69+
) {
70+
CompositionLocalProvider(
71+
LocalKoinScopeContext provides ComposeContextWrapper(scope),
72+
) {
73+
content()
74+
}
75+
}

projects/core/koin-core/src/commonMain/kotlin/org/koin/core/annotation/KoinAnnotations.kt

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,4 +57,27 @@ To foster innovation while gathering valuable community feedback, we introduce n
5757
AnnotationTarget.FIELD,
5858
AnnotationTarget.CONSTRUCTOR,
5959
)
60-
annotation class KoinExperimentalAPI
60+
annotation class KoinExperimentalAPI
61+
62+
63+
/**
64+
Delicate APIs -
65+
APIs marked with @KoinDelicateAPI require careful usage and understanding of their implications. This designation indicates that:
66+
67+
- **Advanced use cases**: The API is designed for specific scenarios that require careful consideration.
68+
- **Potential side effects**: Improper usage may lead to unexpected behavior or runtime issues.
69+
- **Expert knowledge required**: Developers should thoroughly understand the API's behavior and implications before use.
70+
- **Use with caution**: While stable, these APIs require careful attention to their contract and side effects.
71+
*
72+
* @author Arnaud Giuliani
73+
*/
74+
@RequiresOptIn(message = "API marked as @KoinDelicateAPI. This API requires careful usage and understanding of its implications. Use with caution as improper usage may lead to unexpected behavior.", level = RequiresOptIn.Level.WARNING)
75+
@Target(
76+
AnnotationTarget.CLASS,
77+
AnnotationTarget.TYPEALIAS,
78+
AnnotationTarget.FUNCTION,
79+
AnnotationTarget.PROPERTY,
80+
AnnotationTarget.FIELD,
81+
AnnotationTarget.CONSTRUCTOR,
82+
)
83+
annotation class KoinDelicateAPI

0 commit comments

Comments
 (0)