or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

application-setup.mdcontext-access.mddependency-injection.mdindex.mdmodule-management.mdscope-management.md

module-management.mddocs/

0

# Module Management

1

2

Experimental API for dynamically loading and unloading Koin modules based on Compose lifecycle events, enabling dynamic dependency injection that responds to component composition and disposal.

3

4

## Capabilities

5

6

### Remember Koin Modules

7

8

Load and remember Koin modules with configurable lifecycle management, allowing modules to be automatically unloaded when components are forgotten or abandoned.

9

10

```kotlin { .api }

11

/**

12

* Load and remember Koin modules with lifecycle management

13

* @param unloadOnForgotten Unload modules on onForgotten event (optional)

14

* @param unloadOnAbandoned Unload modules on onAbandoned event (optional)

15

* @param unloadModules Unload modules on forgotten/abandoned (default: false)

16

* @param modules Lambda returning list of modules to load

17

*/

18

@KoinExperimentalAPI

19

@Composable

20

inline fun rememberKoinModules(

21

unloadOnForgotten: Boolean? = null,

22

unloadOnAbandoned: Boolean? = null,

23

unloadModules: Boolean = false,

24

crossinline modules: @DisallowComposableCalls () -> List<Module> = { emptyList() }

25

)

26

```

27

28

**Usage Examples:**

29

30

```kotlin

31

@Composable

32

fun DynamicFeature() {

33

// Basic module loading with automatic cleanup

34

rememberKoinModules(unloadModules = true) {

35

listOf(featureModule, networkModule)

36

}

37

38

// Content can now use dependencies from loaded modules

39

val featureService: FeatureService = koinInject()

40

41

FeatureContent(featureService)

42

}

43

44

@Composable

45

fun ConditionalModules(isPreview: Boolean) {

46

rememberKoinModules(

47

unloadOnForgotten = true,

48

unloadOnAbandoned = true

49

) {

50

if (isPreview) {

51

listOf(previewModule, mockModule)

52

} else {

53

listOf(productionModule, realNetworkModule)

54

}

55

}

56

57

Content()

58

}

59

```

60

61

## Module Lifecycle Strategies

62

63

### Automatic Cleanup

64

65

Modules can be automatically unloaded based on Compose RememberObserver events:

66

67

```kotlin

68

@Composable

69

fun AutoCleanupExample() {

70

// Modules unloaded when component leaves composition

71

rememberKoinModules(unloadModules = true) {

72

listOf(

73

temporaryModule,

74

featureSpecificModule

75

)

76

}

77

78

TemporaryFeatureContent()

79

}

80

```

81

82

### Fine-Grained Control

83

84

Control exactly when modules are unloaded:

85

86

```kotlin

87

@Composable

88

fun FineGrainedControl() {

89

rememberKoinModules(

90

unloadOnForgotten = true, // Unload when forgotten (recomposition skip)

91

unloadOnAbandoned = false // Keep loaded when abandoned

92

) {

93

listOf(persistentModule, cacheModule)

94

}

95

96

// Modules persist through abandonment but unload when forgotten

97

PersistentContent()

98

}

99

```

100

101

### Manual Module Management

102

103

Combine with conditional loading for manual control:

104

105

```kotlin

106

@Composable

107

fun ManualModuleControl() {

108

var modulesEnabled by remember { mutableStateOf(false) }

109

110

if (modulesEnabled) {

111

rememberKoinModules(unloadModules = true) {

112

listOf(conditionalModule)

113

}

114

}

115

116

Column {

117

Switch(

118

checked = modulesEnabled,

119

onCheckedChange = { modulesEnabled = it }

120

)

121

122

if (modulesEnabled) {

123

ModuleDependentContent()

124

}

125

}

126

}

127

```

128

129

## Dynamic Module Loading

130

131

### Conditional Module Sets

132

133

Load different modules based on runtime conditions:

134

135

```kotlin

136

@Composable

137

fun ConditionalModuleSets(userRole: UserRole, isDebug: Boolean) {

138

rememberKoinModules(unloadModules = true) {

139

buildList {

140

// Base modules always loaded

141

add(coreModule)

142

143

// Role-based modules

144

when (userRole) {

145

UserRole.ADMIN -> add(adminModule)

146

UserRole.USER -> add(userModule)

147

UserRole.GUEST -> add(guestModule)

148

}

149

150

// Debug modules

151

if (isDebug) {

152

add(debugModule)

153

add(loggingModule)

154

}

155

}

156

}

157

158

RoleBasedContent(userRole)

159

}

160

```

161

162

### Feature-Based Loading

163

164

Load modules based on enabled features:

165

166

```kotlin

167

@Composable

168

fun FeatureBasedLoading(enabledFeatures: Set<Feature>) {

169

rememberKoinModules(

170

unloadOnForgotten = true,

171

unloadOnAbandoned = false

172

) {

173

enabledFeatures.mapNotNull { feature ->

174

when (feature) {

175

Feature.ANALYTICS -> analyticsModule

176

Feature.PUSH_NOTIFICATIONS -> notificationModule

177

Feature.OFFLINE_MODE -> offlineModule

178

Feature.PREMIUM -> premiumModule

179

else -> null

180

}

181

}

182

}

183

184

FeatureContent(enabledFeatures)

185

}

186

```

187

188

## Integration with State

189

190

### State-Driven Module Loading

191

192

React to state changes to load/unload modules:

193

194

```kotlin

195

@Composable

196

fun StateDrivenModules() {

197

var connectionState by remember { mutableStateOf(ConnectionState.OFFLINE) }

198

199

// Modules change based on connection state

200

rememberKoinModules(unloadModules = true) {

201

when (connectionState) {

202

ConnectionState.ONLINE -> listOf(onlineModule, syncModule)

203

ConnectionState.OFFLINE -> listOf(offlineModule, cacheModule)

204

ConnectionState.UNKNOWN -> listOf(fallbackModule)

205

}

206

}

207

208

LaunchedEffect(Unit) {

209

networkStateFlow.collect { state ->

210

connectionState = state

211

}

212

}

213

214

ConnectionAwareContent(connectionState)

215

}

216

```

217

218

### Navigation-Based Loading

219

220

Load modules based on navigation state:

221

222

```kotlin

223

@Composable

224

fun NavigationBasedModules(navController: NavController) {

225

val currentDestination by navController.currentBackStackEntryAsState()

226

227

rememberKoinModules(unloadModules = true) {

228

when (currentDestination?.destination?.route) {

229

"profile" -> listOf(profileModule, userPreferencesModule)

230

"settings" -> listOf(settingsModule, configModule)

231

"shop" -> listOf(shopModule, paymentModule, cartModule)

232

else -> emptyList()

233

}

234

}

235

236

NavHost(navController = navController) {

237

// Navigation destinations

238

}

239

}

240

```

241

242

## Performance Considerations

243

244

### Module Loading Overhead

245

246

Be mindful of module loading performance:

247

248

```kotlin

249

@Composable

250

fun OptimizedModuleLoading(heavyFeatureEnabled: Boolean) {

251

// Only load heavy modules when actually needed

252

if (heavyFeatureEnabled) {

253

rememberKoinModules(unloadModules = true) {

254

listOf(

255

heavyComputationModule,

256

largeDataModule

257

)

258

}

259

260

HeavyFeatureContent()

261

} else {

262

LightweightContent()

263

}

264

}

265

```

266

267

### Module Reuse

268

269

Prevent unnecessary module reloading:

270

271

```kotlin

272

@Composable

273

fun EfficientModuleReuse(config: FeatureConfig) {

274

// Modules only reload when config.moduleSet changes

275

val moduleSet = remember(config.moduleSet) { config.moduleSet }

276

277

rememberKoinModules(unloadModules = true) {

278

moduleSet.map { moduleFactory ->

279

moduleFactory.create()

280

}

281

}

282

283

ConfigurableContent(config)

284

}

285

```

286

287

## Error Handling

288

289

### Module Loading Errors

290

291

Handle module loading failures gracefully:

292

293

```kotlin

294

@Composable

295

fun SafeModuleLoading() {

296

var moduleError by remember { mutableStateOf<String?>(null) }

297

298

try {

299

rememberKoinModules(unloadModules = true) {

300

listOf(

301

riskyModule,

302

dependentModule

303

)

304

}

305

306

NormalContent()

307

308

} catch (e: Exception) {

309

LaunchedEffect(e) {

310

moduleError = "Failed to load modules: ${e.message}"

311

}

312

}

313

314

moduleError?.let { error ->

315

ErrorMessage(error) {

316

moduleError = null

317

}

318

}

319

}

320

```

321

322

### Missing Module Dependencies

323

324

Handle cases where modules have missing dependencies:

325

326

```kotlin

327

@Composable

328

fun RobustModuleLoading() {

329

var fallbackMode by remember { mutableStateOf(false) }

330

331

if (!fallbackMode) {

332

try {

333

rememberKoinModules(unloadModules = true) {

334

listOf(primaryModule, dependencyModule)

335

}

336

337

PrimaryContent()

338

339

} catch (e: BeanCreationException) {

340

LaunchedEffect(e) {

341

fallbackMode = true

342

}

343

}

344

} else {

345

rememberKoinModules(unloadModules = true) {

346

listOf(fallbackModule)

347

}

348

349

FallbackContent()

350

}

351

}

352

```

353

354

## Testing Support

355

356

### Test Module Loading

357

358

Load test-specific modules in test environments:

359

360

```kotlin

361

@Composable

362

fun TestableComponent(isTest: Boolean = false) {

363

rememberKoinModules(unloadModules = true) {

364

if (isTest) {

365

listOf(testModule, mockModule)

366

} else {

367

listOf(productionModule, realModule)

368

}

369

}

370

371

ComponentContent()

372

}

373

374

// In tests

375

@Test

376

fun testComponent() {

377

composeTestRule.setContent {

378

TestableComponent(isTest = true)

379

}

380

381

// Test with mocked dependencies

382

}

383

```

384

385

### Preview Module Loading

386

387

Special modules for Compose previews:

388

389

```kotlin

390

@Preview

391

@Composable

392

fun ComponentPreview() {

393

rememberKoinModules {

394

listOf(previewModule)

395

}

396

397

ComponentContent()

398

}

399

400

val previewModule = module {

401

single<Repository> { MockRepository() }

402

single<ApiService> { PreviewApiService() }

403

}

404

```

405

406

## Best Practices

407

408

1. **Lifecycle Awareness**: Use appropriate unload strategies based on your use case

409

2. **Performance**: Load modules conditionally to avoid unnecessary overhead

410

3. **Error Handling**: Implement fallback strategies for module loading failures

411

4. **State Integration**: Tie module loading to relevant state changes

412

5. **Testing**: Provide test-specific module loading strategies

413

6. **Memory Management**: Use `unloadModules = true` for temporary features

414

7. **Module Design**: Design modules to be independently loadable and unloadable

415

8. **Experimental API**: Remember this is an experimental API and may change in future versions