or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

collections.mdcomposition.mdeffects.mdindex.mdstate-management.md

composition.mddocs/

0

# Composition and Context

1

2

Core composition APIs for building composable functions and managing implicit context propagation through the composition tree. These APIs form the foundation of the Compose runtime system.

3

4

## Capabilities

5

6

### Composable Functions

7

8

The fundamental building blocks of Compose UI.

9

10

```kotlin { .api }

11

/**

12

* Marks functions as composable, enabling them to call other composable functions

13

* and participate in the composition process

14

*/

15

@Target(AnnotationTarget.FUNCTION, AnnotationTarget.TYPE)

16

@Retention(AnnotationRetention.BINARY)

17

annotation class Composable

18

```

19

20

**Usage Examples:**

21

22

```kotlin

23

import androidx.compose.runtime.Composable

24

25

// Basic composable function

26

@Composable

27

fun Greeting(name: String) {

28

Text("Hello, $name!")

29

}

30

31

// Composable with parameters and state

32

@Composable

33

fun Counter(initialValue: Int = 0) {

34

var count by remember { mutableStateOf(initialValue) }

35

36

Column {

37

Text("Count: $count")

38

Button(onClick = { count++ }) {

39

Text("Increment")

40

}

41

}

42

}

43

44

// Composable that accepts other composables

45

@Composable

46

fun Card(

47

modifier: Modifier = Modifier,

48

content: @Composable () -> Unit

49

) {

50

Surface(modifier = modifier) {

51

content()

52

}

53

}

54

```

55

56

### Memory and Caching

57

58

Remember values across recompositions with the remember API.

59

60

```kotlin { .api }

61

/**

62

* Remembers a value across recompositions

63

* The value is recalculated only on first composition or when keys change

64

* @param calculation Function to create the remembered value

65

* @return The remembered value

66

*/

67

@Composable

68

fun <T> remember(calculation: () -> T): T

69

70

/**

71

* Remembers a value with a single dependency key

72

* @param key1 Dependency key - value is recalculated when this changes

73

* @param calculation Function to create the remembered value

74

* @return The remembered value

75

*/

76

@Composable

77

fun <T> remember(key1: Any?, calculation: () -> T): T

78

79

/**

80

* Remembers a value with multiple dependency keys

81

*/

82

@Composable

83

fun <T> remember(key1: Any?, key2: Any?, calculation: () -> T): T

84

85

@Composable

86

fun <T> remember(key1: Any?, key2: Any?, key3: Any?, calculation: () -> T): T

87

88

/**

89

* Remembers a value with variable number of dependency keys

90

*/

91

@Composable

92

fun <T> remember(vararg keys: Any?, calculation: () -> T): T

93

```

94

95

**Usage Examples:**

96

97

```kotlin

98

@Composable

99

fun RememberExample(userId: String, settings: AppSettings) {

100

// Remember expensive computation

101

val processedData = remember(userId) {

102

expensiveDataProcessing(userId)

103

}

104

105

// Remember stateful objects

106

val listState = remember { LazyListState() }

107

val focusRequester = remember { FocusRequester() }

108

109

// Remember with multiple keys

110

val cachedResult = remember(userId, settings.cacheEnabled) {

111

if (settings.cacheEnabled) {

112

getCachedData(userId)

113

} else {

114

getServerData(userId)

115

}

116

}

117

118

// Remember lambda functions to avoid recreating them

119

val onItemClick = remember(userId) {

120

{ itemId: String -> handleItemClick(userId, itemId) }

121

}

122

}

123

```

124

125

### Composition Locals

126

127

Provide implicit values that can be accessed by any composable in the subtree.

128

129

```kotlin { .api }

130

/**

131

* Provides values to CompositionLocal instances for the content block

132

* @param values Provided values as key-value pairs

133

* @param content Composable content that can access the provided values

134

*/

135

@Composable

136

fun CompositionLocalProvider(

137

vararg values: ProvidedValue<*>,

138

content: @Composable () -> Unit

139

)

140

141

/**

142

* Abstract base class for CompositionLocal

143

*/

144

abstract class CompositionLocal<T> {

145

/**

146

* Current value of this CompositionLocal

147

*/

148

val current: T

149

@Composable get

150

151

/**

152

* Provides a value for this CompositionLocal

153

*/

154

infix fun provides(value: T): ProvidedValue<T>

155

}

156

157

/**

158

* CompositionLocal that never changes - more efficient for static values

159

*/

160

abstract class StaticProvidableCompositionLocal<T> : CompositionLocal<T>()

161

162

/**

163

* CompositionLocal that can change and notifies composables when it does

164

*/

165

abstract class DynamicProvidableCompositionLocal<T> : CompositionLocal<T>()

166

167

/**

168

* Base class for CompositionLocal instances that can provide values

169

*/

170

abstract class ProvidableCompositionLocal<T> : CompositionLocal<T>()

171

172

/**

173

* Represents a key-value pair for providing CompositionLocal values

174

*/

175

data class ProvidedValue<T>(

176

val compositionLocal: CompositionLocal<T>,

177

val value: T

178

)

179

```

180

181

**Usage Examples:**

182

183

```kotlin

184

// Define composition locals

185

val LocalUserPreferences = compositionLocalOf { UserPreferences() }

186

val LocalTheme = staticCompositionLocalOf { AppTheme.Light }

187

188

@Composable

189

fun App() {

190

val userPrefs = remember { loadUserPreferences() }

191

val currentTheme = remember(userPrefs.themeMode) {

192

getThemeForMode(userPrefs.themeMode)

193

}

194

195

CompositionLocalProvider(

196

LocalUserPreferences provides userPrefs,

197

LocalTheme provides currentTheme

198

) {

199

MainScreen()

200

}

201

}

202

203

@Composable

204

fun MainScreen() {

205

// Access composition locals

206

val theme = LocalTheme.current

207

val userPrefs = LocalUserPreferences.current

208

209

Surface(color = theme.backgroundColor) {

210

if (userPrefs.showWelcome) {

211

WelcomeMessage()

212

}

213

ContentArea()

214

}

215

}

216

217

@Composable

218

fun WelcomeMessage() {

219

val userPrefs = LocalUserPreferences.current

220

Text(

221

text = "Welcome, ${userPrefs.userName}!",

222

color = LocalTheme.current.textColor

223

)

224

}

225

```

226

227

### Creating Composition Locals

228

229

Define your own CompositionLocal instances.

230

231

```kotlin { .api }

232

/**

233

* Creates a CompositionLocal with change notifications

234

* More overhead but allows dynamic updates

235

* @param policy Mutation policy for detecting changes

236

* @param defaultFactory Optional factory for default value

237

* @return ProvidableComposionLocal instance

238

*/

239

fun <T> compositionLocalOf(

240

policy: SnapshotMutationPolicy<T> = structuralEqualityPolicy(),

241

defaultFactory: (() -> T)? = null

242

): ProvidableCompositionLocal<T>

243

244

/**

245

* Creates a CompositionLocal that never changes

246

* More efficient for static values

247

* @param defaultFactory Optional factory for default value

248

* @return ProvidableCompositionLocal instance

249

*/

250

fun <T> staticCompositionLocalOf(

251

defaultFactory: (() -> T)? = null

252

): ProvidableCompositionLocal<T>

253

```

254

255

**Usage Examples:**

256

257

```kotlin

258

// Dynamic composition local (can change)

259

val LocalUser = compositionLocalOf<User?> { null }

260

261

// Static composition local (never changes)

262

val LocalAppConfig = staticCompositionLocalOf {

263

AppConfig.default()

264

}

265

266

// Composition local with default value

267

val LocalAnalytics = compositionLocalOf {

268

NoOpAnalytics() // Default implementation

269

}

270

271

@Composable

272

fun MyApp() {

273

val currentUser = remember { getCurrentUser() }

274

275

CompositionLocalProvider(

276

LocalUser provides currentUser,

277

LocalAnalytics provides RealAnalytics()

278

) {

279

NavigationHost()

280

}

281

}

282

283

@Composable

284

fun UserProfile() {

285

val user = LocalUser.current

286

val analytics = LocalAnalytics.current

287

288

if (user != null) {

289

LaunchedEffect(user.id) {

290

analytics.trackScreenView("UserProfile", user.id)

291

}

292

293

Column {

294

Text("Name: ${user.name}")

295

Text("Email: ${user.email}")

296

}

297

} else {

298

LoginPrompt()

299

}

300

}

301

```

302

303

### Composition Tree Navigation

304

305

Access and manipulate the composition tree structure.

306

307

```kotlin { .api }

308

/**

309

* Returns the current Composer instance

310

*/

311

val currentComposer: Composer

312

@Composable get

313

314

/**

315

* Returns the current recompose scope

316

*/

317

val currentRecomposeScope: RecomposeScope

318

@Composable get

319

320

/**

321

* Interface for controlling recomposition

322

*/

323

interface RecomposeScope {

324

/**

325

* Invalidates this scope, causing it to recompose

326

*/

327

fun invalidate()

328

}

329

330

/**

331

* The Composer is the interface between the composable functions and the composition tree

332

*/

333

interface Composer {

334

/**

335

* Whether the composer is currently inserting content into the composition

336

*/

337

val inserting: Boolean

338

339

/**

340

* Whether the composer is currently skipping content during recomposition

341

*/

342

val skipping: Boolean

343

}

344

```

345

346

**Usage Examples:**

347

348

```kotlin

349

@Composable

350

fun DebuggingExample() {

351

val scope = currentRecomposeScope

352

353

Button(

354

onClick = {

355

// Force recomposition of this scope

356

scope.invalidate()

357

}

358

) {

359

Text("Force Recompose")

360

}

361

}

362

363

@Composable

364

fun ComposerExample() {

365

val composer = currentComposer

366

367

// Access composer information (advanced usage)

368

SideEffect {

369

println("Composer inserting: ${composer.inserting}")

370

println("Composer skipping: ${composer.skipping}")

371

}

372

}

373

```

374

375

### Composition Annotations

376

377

Control composition behavior with annotations.

378

379

```kotlin { .api }

380

/**

381

* Marks composables that shouldn't restart on recomposition

382

* Use for performance optimization when restart isn't needed

383

*/

384

@Target(AnnotationTarget.FUNCTION)

385

@Retention(AnnotationRetention.BINARY)

386

annotation class NonRestartableComposable

387

388

/**

389

* Marks composables that only read values and don't participate in recomposition

390

* Used for optimization - these composables won't be recomposed

391

*/

392

@Target(AnnotationTarget.FUNCTION)

393

@Retention(AnnotationRetention.BINARY)

394

annotation class ReadOnlyComposable

395

396

/**

397

* Marks APIs used by the Compose compiler

398

* These are internal APIs not intended for direct use

399

*/

400

@Target(

401

AnnotationTarget.CLASS,

402

AnnotationTarget.FUNCTION,

403

AnnotationTarget.PROPERTY,

404

AnnotationTarget.TYPEALIAS

405

)

406

@Retention(AnnotationRetention.BINARY)

407

annotation class ComposeCompilerApi

408

```

409

410

**Usage Examples:**

411

412

```kotlin

413

// Non-restartable composable for performance

414

@NonRestartableComposable

415

@Composable

416

fun StaticHeader() {

417

Text("App Title") // Never changes, doesn't need restart

418

}

419

420

// Read-only composable that doesn't trigger recomposition

421

@ReadOnlyComposable

422

@Composable

423

fun currentPlatform(): Platform {

424

return Platform.current // Static value

425

}

426

427

@Composable

428

fun OptimizedScreen() {

429

StaticHeader() // Won't restart on recomposition

430

431

val platform = currentPlatform() // Won't cause recomposition

432

433

PlatformSpecificContent(platform)

434

}

435

```

436

437

## Advanced Composition Patterns

438

439

### Custom Remember Implementation

440

441

Create custom remember-like behavior.

442

443

```kotlin

444

@Composable

445

fun <T> rememberWithLifecycle(

446

lifecycle: Lifecycle,

447

calculation: () -> T

448

): T {

449

return remember(lifecycle.currentState) {

450

calculation()

451

}

452

}

453

454

@Composable

455

fun <T> rememberCached(

456

key: String,

457

calculation: () -> T

458

): T {

459

return remember(key) {

460

cache.get(key) ?: calculation().also { cache.put(key, it) }

461

}

462

}

463

```

464

465

### Conditional Composition

466

467

Patterns for conditional composition based on state.

468

469

```kotlin

470

@Composable

471

fun ConditionalComposition(showDetails: Boolean) {

472

if (showDetails) {

473

DetailedView()

474

} else {

475

SummaryView()

476

}

477

}

478

479

@Composable

480

fun <T> ConditionalProvider(

481

condition: Boolean,

482

value: T,

483

content: @Composable () -> Unit

484

) {

485

if (condition) {

486

CompositionLocalProvider(LocalMyValue provides value) {

487

content()

488

}

489

} else {

490

content()

491

}

492

}

493

```