0Pricing
Kotlin Academy · Pelajaran

Mengubah Flow Dingin Menjadi Aktif dengan shareIn dan stateIn

Ubah Flow dingin menjadi aliran aktif dengan operator berbagi.

Mengubah Flow Dingin Menjadi Aktif dengan shareIn dan stateIn adalah pelajaran Kotlin Academy gratis di CoddyKit. Ini adalah pelajaran 3 dari 4. Kamu bisa membaca pelajaran lengkapnya di bawah secara gratis — lalu praktikkan langsung di browser dengan editor kode bawaan dan tutor AI 24/7. Ini adalah bagian dari jalur belajar Kotlin Academy, dan progresmu tersinkronisasi di web dan aplikasi CoddyKit. Kursus Kotlin Academy mencakup 4 pelajaran total.

Aliran Dingin vs Panas

Aliran dingin dimulai ulang untuk setiap pengumpul, sedangkan aliran panas berbagi satu langganan sumber. Mengubah aliran dingin menjadi aliran panas mencegah pekerjaan berulang saat beberapa pengumpul berlangganan.

import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun expensiveFlow() = flow {
    println("Starting upstream work")  // runs once if shared
    repeat(3) { delay(100); emit(it) }
}
fun main() = runBlocking {
    val cold = expensiveFlow()
    // Two collectors = two executions:
    launch { cold.collect { } }
    launch { cold.collect { } }
    delay(500)
    coroutineContext.cancelChildren()
}

Dasar-Dasar shareIn

flow.shareIn(scope, started, replay) mengubah Flow dingin menjadi SharedFlow dengan berbagi satu langganan sumber.

import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
    val cold = flow {
        println("Upstream started once")
        repeat(5) { delay(100); emit(it) }
    }
    val hot = cold.shareIn(this, SharingStarted.Eagerly, replay = 0)
    launch { hot.collect { println("A: $it") } }
    launch { hot.collect { println("B: $it") } }
    delay(600)
    coroutineContext.cancelChildren()
}

Dasar-Dasar stateIn

flow.stateIn(scope, started, initialValue) mengubahnya menjadi StateFlow — selalu memiliki nilai dan memutar ulang 1 nilai.

import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
    val cold = flow { delay(100); emit(42) }
    val state: StateFlow<Int> = cold.stateIn(
        scope = this,
        started = SharingStarted.Eagerly,
        initialValue = 0
    )
    println(state.value)  // 0 immediately
    delay(200)
    println(state.value)  // 42 after upstream emits
    coroutineContext.cancelChildren()
}

SharingStarted.Eagerly

Eagerly: aliran sumber segera dimulai saat shareIn/stateIn dipanggil, terlepas dari ada tidaknya pelanggan.

import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
    val flow = flow {
        println("Eagerly started")
        emit(1)
    }.shareIn(this, SharingStarted.Eagerly)
    // Upstream already running even before any collect
    delay(50)
    launch { flow.collect { println(it) } }
    delay(100)
    coroutineContext.cancelChildren()
}

SharingStarted.Lazily

Lazily: aliran sumber dimulai saat pelanggan pertama berlangganan dan tidak pernah berhenti, bahkan jika jumlah pelanggan turun menjadi nol.

import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
    val flow = flow {
        println("Lazily started on first subscriber")
        repeat(3) { delay(100); emit(it) }
    }.shareIn(this, SharingStarted.Lazily, replay = 1)
    delay(50)  // no subscriber yet — not started
    launch { flow.collect { println(it) } }  // triggers start
    delay(400)
    coroutineContext.cancelChildren()
}

SharingStarted.WhileSubscribed

WhileSubscribed(stopTimeout): aliran sumber dimulai saat pelanggan pertama bergabung dan berhenti stopTimeout milidetik setelah pelanggan terakhir pergi. Sangat cocok untuk ViewModels.

import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
    val flow = flow {
        println("Started")
        repeat(10) { delay(100); emit(it) }
    }.shareIn(this, SharingStarted.WhileSubscribed(500))
    val job = launch { flow.collect { print("$it ") } }
    delay(300)
    job.cancel()    // subscriber left
    delay(200)      // within 500ms stop timeout — still running
    launch { flow.collect { print("resume $it ") } }
    delay(500)
    coroutineContext.cancelChildren()
}

Pola ViewModel yang Umum

Dalam ViewModels Android, ubah aliran dari repositori dengan stateIn(viewModelScope, WhileSubscribed(5000), initialValue) agar dapat dibagikan dan tetap bertahan saat konfigurasi berubah.

import kotlinx.coroutines.flow.*
// In ViewModel:
// val uiState: StateFlow<UiState> = repository
//     .dataFlow()
//     .map { UiState.Success(it) }
//     .stateIn(
//         scope = viewModelScope,
//         started = SharingStarted.WhileSubscribed(5_000),
//         initialValue = UiState.Loading
//     )
fun main() { println("WhileSubscribed(5000) is the recommended ViewModel pattern") }

shareIn vs stateIn

shareIn → SharedFlow (tanpa nilai saat ini, pemutaran ulang yang dapat dikonfigurasi). stateIn → StateFlow (selalu memiliki nilai, replay=1). Pilih berdasarkan apakah konsumen memerlukan status saat ini.

import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
    val cold = (1..3).asFlow().map { it * 10 }

    // SharedFlow — no initial value:
    val shared: SharedFlow<Int> = cold.shareIn(this, SharingStarted.Eagerly, replay = 1)

    // StateFlow — always has a value:
    val state: StateFlow<Int> = cold.stateIn(this, SharingStarted.Eagerly, 0)

    delay(100)
    println("shared cache: ${shared.replayCache}")
    println("state value: ${state.value}")
    coroutineContext.cancelChildren()
}

Kompromi Cache Pemutaran Ulang

Pemutaran ulang yang lebih tinggi memungkinkan pelanggan yang bergabung terlambat melihat lebih banyak riwayat, tetapi menggunakan lebih banyak memori. Untuk status UI, replay=1 (stateIn) sudah cukup. Untuk log peristiwa, pemutaran ulang yang lebih tinggi mungkin diperlukan.

import kotlinx.coroutines.flow.*
// replay=0: no history, only future events
// replay=1: last value (equivalent to stateIn)
// replay=N: last N events — use for message feeds, logs

// Trade-off: memory vs subscriber freshness
fun main() { println("Choose replay based on late-subscriber requirements") }

Risiko Aliran Tanpa Berbagi

Tanpa berbagi, setiap pengumpul Compose atau pengamat ViewModel menjalankan kembali aliran sumber — panggilan jaringan dan kueri basis data menjadi berulang. Selalu bagikan aliran yang mahal.

import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun expensiveApi() = flow {
    println("API CALL")  // without sharing: once per collector
    emit("data")
}
fun main() = runBlocking {
    val shared = expensiveApi().shareIn(this, SharingStarted.Lazily, replay = 1)
    launch { shared.collect { } }  // one API call, shared
    launch { shared.collect { } }  // same emission
    delay(200)
    coroutineContext.cancelChildren()
}

Pembersihan Sumber Daya saat Berbagi

Saat cakupan aliran yang dibagikan dibatalkan, aliran sumber juga dibatalkan dan blok finally-nya dijalankan — sumber daya dibersihkan dengan benar.

import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun resourceFlow() = flow {
    try { repeat(10) { delay(100); emit(it) } }
    finally { println("Upstream cleaned up") }
}
fun main() = runBlocking {
    val scope = CoroutineScope(SupervisorJob())
    val shared = resourceFlow().shareIn(scope, SharingStarted.Eagerly)
    launch { shared.collect { print("$it ") } }
    delay(250)
    scope.cancel()  // upstream cleanup runs
    delay(100)
}

Pemeriksaan Cepat

Strategi SharingStarted mana yang direkomendasikan untuk ViewModels Android?

Ringkasan

shareIn mengubah aliran menjadi SharedFlow, sedangkan stateIn mengubahnya menjadi StateFlow. Gunakan WhileSubscribed dalam ViewModels untuk menghemat sumber daya. Berbagi mencegah eksekusi aliran sumber yang berulang saat beberapa pengumpul berlangganan.

Pertanyaan yang Sering Diajukan

Apakah pelajaran “Mengubah Flow Dingin Menjadi Aktif dengan shareIn dan stateIn” gratis?

Ya — teks lengkap “Mengubah Flow Dingin Menjadi Aktif dengan shareIn dan stateIn” gratis dibaca di sini di web. Untuk praktiknya secara interaktif (editor kode bawaan dan tutor AI 24/7) dan buka sisa kursus Kotlin Academy, upgrade ke CoddyKit PRO. Kursus Kotlin Academy mencakup 4 pelajaran total.

Apa yang akan aku pelajari di “Mengubah Flow Dingin Menjadi Aktif dengan shareIn dan stateIn”?

Ubah Flow dingin menjadi aliran aktif dengan operator berbagi. Kamu berlatih Kotlin Academy dengan kode praktik yang langsung kamu jalankan di browser, dan tutor AI 24/7 menjawab pertanyaanmu saat kamu mengerjakan pelajaran ini.

Apakah aku perlu pengalaman untuk memulai Kotlin Academy?

Tidak diperlukan pengalaman sebelumnya. Kotlin Academy di CoddyKit dirancang untuk pemula hingga pelajar tingkat lanjut, jadi kamu bisa memulai di sini atau dari awal dan belajar sesuai kecepatan kamu sendiri. Ini adalah pelajaran 3 dari 4.

Berapa lama pelajaran “Mengubah Flow Dingin Menjadi Aktif dengan shareIn dan stateIn” memakan waktu?

Sebagian besar pelajaran CoddyKit memakan waktu sekitar 5–10 menit. Setiap pelajaran ringkas dan interaktif, jadi kamu membuat kemajuan stabil dan melanjutkan dari tempat kamu tinggalkan di web dan aplikasi.

Bisakah aku menulis dan menjalankan kode dalam pelajaran Kotlin Academy ini?

Ya. Setiap pelajaran Kotlin Academy menyertakan editor kode bawaan, jadi kamu menulis dan menjalankan kode nyata langsung di browser dan mendapatkan umpan balik AI instan — tidak diperlukan penyiapan lokal.

Semua pelajaran dalam kursus ini

  1. StateFlow: Penampung Status Aktif untuk UI
  2. SharedFlow: Bus Peristiwa dan Peristiwa Sekali Jalan
  3. Mengubah Flow Dingin Menjadi Aktif dengan shareIn dan stateIn
  4. Menguji StateFlow dan SharedFlow dengan Turbine
← Kembali ke Kotlin Academy