UI ที่ทันสมัยมักจะไม่คงที่ สถานะของ UI เปลี่ยนแปลงเมื่อผู้ใช้ โต้ตอบกับ UI หรือเมื่อแอปต้องแสดงข้อมูลใหม่
เอกสารนี้ระบุหลักเกณฑ์ในการสร้างและการจัดการ UI สุดท้าย คุณควรทำดังนี้
- รู้ว่าควรใช้ API ใดเพื่อสร้างสถานะ UI ขึ้นอยู่กับ ลักษณะแหล่งที่มาของการเปลี่ยนแปลงของรัฐที่เจ้าของรัฐใช้ได้ ตามหลักการในโฟลว์ข้อมูลที่ไปในทิศทางเดียวกัน
- ทราบว่าคุณควรกำหนดขอบเขตสถานะ UI อย่างไรเพื่อคำนึงถึง ทรัพยากรระบบ
- ทราบว่าควรแสดงสถานะ UI อย่างไรเพื่อให้ใช้งานผ่าน UI
โดยพื้นฐานแล้ว การผลิตในระดับรัฐคือการประยุกต์ใช้การเปลี่ยนแปลงเหล่านี้แบบค่อยเป็นค่อยไป เป็นสถานะ UI สถานะจะปรากฏอยู่เสมอ และมีการเปลี่ยนแปลงตามผลของเหตุการณ์ ความแตกต่างระหว่างเหตุการณ์และสถานะสรุปไว้ในตารางด้านล่าง
กิจกรรม | รัฐ |
---|---|
เกิดขึ้นชั่วคราว คาดเดาไม่ได้ และมีอยู่เป็นระยะเวลาจำกัด | พร้อมใช้งานเสมอ |
อินพุตของเวอร์ชันที่ใช้งานจริง | เอาต์พุตของเวอร์ชันที่ใช้งานจริง |
ผลิตภัณฑ์ของ UI หรือแหล่งที่มาอื่นๆ | มีการใช้งานโดย UI |
วิธีช่วยจำได้อย่างดีในการสรุปสิ่งข้างต้นคือสถานะคือ เหตุการณ์ที่เกิดขึ้น แผนภาพด้านล่างช่วยให้เห็นภาพการเปลี่ยนแปลงสถานะเมื่อมีเหตุการณ์เกิดขึ้นในไทม์ไลน์ แต่ละเหตุการณ์จะได้รับการประมวลผลโดยเจ้าของสถานะที่เหมาะสม และส่งผลให้เกิด การเปลี่ยนสถานะ:
![เหตุการณ์กับสถานะ](https://developer.android.com/static/images/topic/architecture/ui-layer/events-vs-state.png?authuser=4&hl=th)
กิจกรรมอาจมาจาก
- ผู้ใช้: ในขณะที่โต้ตอบกับ UI ของแอป
- แหล่งที่มาอื่นๆ ของการเปลี่ยนแปลงสถานะ: API ที่นำเสนอข้อมูลแอปจาก UI โดเมน หรือชั้นข้อมูล เช่น เหตุการณ์ระยะหมดเวลาของแถบแสดงข้อความ กรณีการใช้งาน หรือ ที่เก็บตามลำดับ
ไปป์ไลน์การสร้างสถานะ UI
เวอร์ชันที่ใช้งานจริงในแอป Android ถือว่าเป็นไปป์ไลน์การประมวลผล ซึ่งประกอบด้วย:
- อินพุต: แหล่งที่มาของการเปลี่ยนแปลงสถานะ ซึ่งอาจเป็น
- ภายในเลเยอร์ UI: เหตุการณ์เหล่านี้อาจเป็นเหตุการณ์ของผู้ใช้ เช่น ผู้ใช้ป้อน
ชื่อสำหรับ "สิ่งที่ต้องทำ" ในแอปการจัดการงาน หรือ API ที่
สิทธิ์เข้าถึงตรรกะ UI ที่กระตุ้นให้เกิดการเปลี่ยนแปลงสถานะ UI ตัวอย่างเช่น
การเรียกใช้เมธอด
open
ในDrawerState
ใน Jetpack Compose - ภายนอกเลเยอร์ UI: ข้อมูลเหล่านี้คือแหล่งที่มาจากโดเมนหรือข้อมูล
ที่ทำให้สถานะของ UI เปลี่ยนไป เช่น ข่าวที่จบแล้ว
ที่โหลดจาก
NewsRepository
หรือเหตุการณ์อื่นๆ - ทั้งหมดที่กล่าวมาข้างต้น
- ภายในเลเยอร์ UI: เหตุการณ์เหล่านี้อาจเป็นเหตุการณ์ของผู้ใช้ เช่น ผู้ใช้ป้อน
ชื่อสำหรับ "สิ่งที่ต้องทำ" ในแอปการจัดการงาน หรือ API ที่
สิทธิ์เข้าถึงตรรกะ UI ที่กระตุ้นให้เกิดการเปลี่ยนแปลงสถานะ UI ตัวอย่างเช่น
การเรียกใช้เมธอด
- ผู้ถือรัฐ: ประเภทที่ใช้ตรรกะทางธุรกิจและ/หรือ ตรรกะ UI ไปยังแหล่งที่มาของการเปลี่ยนแปลงสถานะและประมวลผลเหตุการณ์ของผู้ใช้เพื่อสร้าง สถานะ UI
- เอาต์พุต: สถานะ UI ที่แอปแสดงผลได้เพื่อให้ผู้ใช้ ข้อมูลที่ต้องการได้อีกด้วย
![ไปป์ไลน์การผลิตสถานะ](https://developer.android.com/static/images/topic/architecture/ui-layer/state-production-pipeline.png?authuser=4&hl=th)
API การผลิตสถานะ
API หลักที่ใช้ในเวอร์ชันที่ใช้งานจริงจะมี 2 แบบ ขึ้นอยู่กับขั้นตอนของ ไปป์ไลน์ที่คุณใช้อยู่:
ขั้นตอนไปป์ไลน์ | API |
---|---|
อินพุต | คุณควรใช้ API แบบอะซิงโครนัสในการทำงานนอกเธรด UI เพื่อทำให้ UI มีความกระตุกอยู่เสมอ เช่น Coroutines หรือ Flows ใน Kotlin และ RxJava หรือ Callback ในภาษาโปรแกรม Java |
เอาต์พุต | คุณควรใช้ API ผู้ถือข้อมูลที่ได้รับอนุญาตให้สังเกตพฤติกรรมผู้ใช้ได้เพื่อทำให้ UI เป็นโมฆะและแสดง UI อีกครั้งเมื่อมีการเปลี่ยนแปลงสถานะ ตัวอย่างเช่น StateFlow, Compose State หรือ LiveData ผู้ถือข้อมูลที่สังเกตได้จะรับประกันว่า UI จะมีสถานะ UI ที่จะแสดงบนหน้าจอเสมอ |
จากตัวเลือกทั้ง 2 อย่าง ตัวเลือก API แบบอะซิงโครนัสสำหรับอินพุตมีอิทธิพลมากกว่า ลักษณะของไปป์ไลน์การผลิตของรัฐมากกว่าตัวเลือก API ที่สังเกตได้ สำหรับเอาต์พุต นั่นเป็นเพราะอินพุตเป็นตัวกำหนดประเภทการประมวลผลข้อมูลที่อาจ กับไปป์ไลน์
การประกอบกระบวนการผลิตของรัฐ
ส่วนถัดไปจะกล่าวถึงเทคนิคการสร้างสถานะ ซึ่งเหมาะสำหรับ และ API เอาต์พุตที่ตรงกัน ไปป์ไลน์ที่ใช้งานจริงแต่ละรัฐคือ ชุดค่าผสมของอินพุตและเอาต์พุต และควรมีลักษณะดังนี้
- การทราบอายุการใช้งาน: ในกรณีที่ UI ไม่ปรากฏหรือไม่ทํางานจริง ไปป์ไลน์การผลิตสถานะไม่ควรใช้ทรัพยากรใดๆ ยกเว้นอย่างชัดแจ้ง ต้องระบุ
- ใช้งานง่าย: UI ควรสามารถแสดงผล UI ที่สร้างขึ้นได้อย่างง่ายดาย ข้อควรพิจารณาสำหรับเอาต์พุตของไปป์ไลน์เวอร์ชันที่ใช้งานจริงของรัฐจะ แตกต่างกันไปตาม View API ต่างๆ เช่น ระบบ View หรือ Jetpack Compose
อินพุตในไปป์ไลน์การผลิตสถานะ
อินพุตในไปป์ไลน์การผลิตสถานะอาจระบุแหล่งที่มาของสถานะ เปลี่ยนผ่าน:
- การดำเนินการแบบจุดเดียวซึ่งอาจเป็นการทำงานแบบซิงโครนัสหรืออะซิงโครนัส เช่น
การเรียกไปยังฟังก์ชัน
suspend
- API ของสตรีม เช่น
Flows
- ทั้งหมดที่กล่าวมา
ส่วนต่อไปนี้ครอบคลุมวิธีประกอบไปป์ไลน์การผลิตสถานะ สำหรับข้อมูลข้างต้นแต่ละรายการ
API แบบ One-shot เป็นแหล่งที่มาของการเปลี่ยนแปลงสถานะ
ใช้ MutableStateFlow
API เป็นแบบที่สังเกตได้และเปลี่ยนแปลงได้
คอนเทนเนอร์ของสถานะ ในแอป Jetpack Compose คุณอาจลองใช้
mutableStateOf
โดยเฉพาะเมื่อทำงานร่วมกับ
Compose Text API API ทั้ง 2 แบบเสนอวิธีที่ปลอดภัย
อัปเดตระดับย่อยของค่าที่โฮสต์ไว้ ไม่ว่าการอัปเดตนั้น
แบบซิงโครนัสหรืออะซิงโครนัส
เช่น พิจารณาการอัปเดตสถานะในแอปทอยลูกเต๋าแบบง่ายๆ แต่ละม้วน
ลูกเต๋าที่ได้จากผู้ใช้จะเรียกการทำงานพร้อมกัน
Random.nextInt()
และผลลัพธ์จะถูกเขียนลงใน
สถานะ UI
โฟลว์สถานะ
data class DiceUiState(
val firstDieValue: Int? = null,
val secondDieValue: Int? = null,
val numberOfRolls: Int = 0,
)
class DiceRollViewModel : ViewModel() {
private val _uiState = MutableStateFlow(DiceUiState())
val uiState: StateFlow<DiceUiState> = _uiState.asStateFlow()
// Called from the UI
fun rollDice() {
_uiState.update { currentState ->
currentState.copy(
firstDieValue = Random.nextInt(from = 1, until = 7),
secondDieValue = Random.nextInt(from = 1, until = 7),
numberOfRolls = currentState.numberOfRolls + 1,
)
}
}
}
สถานะการเขียน
@Stable
interface DiceUiState {
val firstDieValue: Int?
val secondDieValue: Int?
val numberOfRolls: Int?
}
private class MutableDiceUiState: DiceUiState {
override var firstDieValue: Int? by mutableStateOf(null)
override var secondDieValue: Int? by mutableStateOf(null)
override var numberOfRolls: Int by mutableStateOf(0)
}
class DiceRollViewModel : ViewModel() {
private val _uiState = MutableDiceUiState()
val uiState: DiceUiState = _uiState
// Called from the UI
fun rollDice() {
_uiState.firstDieValue = Random.nextInt(from = 1, until = 7)
_uiState.secondDieValue = Random.nextInt(from = 1, until = 7)
_uiState.numberOfRolls = _uiState.numberOfRolls + 1
}
}
การเปลี่ยนแปลงสถานะ UI จากการเรียกแบบไม่พร้อมกัน
สำหรับการเปลี่ยนแปลงสถานะที่ต้องการผลลัพธ์แบบไม่พร้อมกัน ให้เรียกใช้ Coroutine ใน
ที่เหมาะสมCoroutineScope
วิธีนี้จะช่วยให้แอปทิ้งงานได้เมื่อ
CoroutineScope
ถูกยกเลิก จากนั้นเจ้าของรัฐจะเขียนผลลัพธ์ของ
ระงับการเรียกใช้เมธอดใน API ที่สังเกตได้ซึ่งใช้เพื่อแสดงสถานะ UI
ตัวอย่างเช่น ลองพิจารณา AddEditTaskViewModel
ใน
ตัวอย่างสถาปัตยกรรม เมื่อเมธอด saveTask()
ที่ถูกระงับ
จะบันทึกงานแบบไม่พร้อมกัน เมธอด update
ใน
MutableStateFlow เผยแพร่การเปลี่ยนแปลงสถานะเป็นสถานะ UI
โฟลว์สถานะ
data class AddEditTaskUiState(
val title: String = "",
val description: String = "",
val isTaskCompleted: Boolean = false,
val isLoading: Boolean = false,
val userMessage: String? = null,
val isTaskSaved: Boolean = false
)
class AddEditTaskViewModel(...) : ViewModel() {
private val _uiState = MutableStateFlow(AddEditTaskUiState())
val uiState: StateFlow<AddEditTaskUiState> = _uiState.asStateFlow()
private fun createNewTask() {
viewModelScope.launch {
val newTask = Task(uiState.value.title, uiState.value.description)
try {
tasksRepository.saveTask(newTask)
// Write data into the UI state.
_uiState.update {
it.copy(isTaskSaved = true)
}
}
catch(cancellationException: CancellationException) {
throw cancellationException
}
catch(exception: Exception) {
_uiState.update {
it.copy(userMessage = getErrorMessage(exception))
}
}
}
}
}
สถานะการเขียน
@Stable
interface AddEditTaskUiState {
val title: String
val description: String
val isTaskCompleted: Boolean
val isLoading: Boolean
val userMessage: String?
val isTaskSaved: Boolean
}
private class MutableAddEditTaskUiState : AddEditTaskUiState() {
override var title: String by mutableStateOf("")
override var description: String by mutableStateOf("")
override var isTaskCompleted: Boolean by mutableStateOf(false)
override var isLoading: Boolean by mutableStateOf(false)
override var userMessage: String? by mutableStateOf<String?>(null)
override var isTaskSaved: Boolean by mutableStateOf(false)
}
class AddEditTaskViewModel(...) : ViewModel() {
private val _uiState = MutableAddEditTaskUiState()
val uiState: AddEditTaskUiState = _uiState
private fun createNewTask() {
viewModelScope.launch {
val newTask = Task(uiState.value.title, uiState.value.description)
try {
tasksRepository.saveTask(newTask)
// Write data into the UI state.
_uiState.isTaskSaved = true
}
catch(cancellationException: CancellationException) {
throw cancellationException
}
catch(exception: Exception) {
_uiState.userMessage = getErrorMessage(exception))
}
}
}
}
การเปลี่ยนสถานะ UI จากชุดข้อความเบื้องหลัง
แนะนำให้เปิดใช้ Coroutines ในผู้มอบหมายงานหลักสำหรับการผลิต
ของสถานะ UI นั่นคือนอกบล็อก withContext
ในข้อมูลโค้ด
ที่ด้านล่าง อย่างไรก็ตาม หากคุณต้องการอัปเดตสถานะ UI ในพื้นหลังอื่น
บริบทเพิ่มเติม คุณสามารถทำได้โดยใช้ API ต่อไปนี้
- ใช้เมธอด
withContext
เพื่อเรียกใช้ Coroutines ใน ในบริบทที่แตกต่างกัน - เมื่อใช้
MutableStateFlow
ให้ใช้เมธอดupdate
เป็น ตามปกติ - เมื่อใช้สถานะการเขียน ให้ใช้
Snapshot.withMutableSnapshot
เพื่อ รับประกันการอัปเดตระดับอะตอมของสถานะในบริบทที่เกิดขึ้นพร้อมกัน
ตัวอย่างเช่น สมมติว่าในข้อมูลโค้ด DiceRollViewModel
ด้านล่างนี้
SlowRandom.nextInt()
เป็น suspend
ที่มีการคำนวณอย่างหนัก
ที่ต้องเรียกใช้จาก Coroutine ที่ผูกกับ CPU
โฟลว์สถานะ
class DiceRollViewModel(
private val defaultDispatcher: CoroutineScope = Dispatchers.Default
) : ViewModel() {
private val _uiState = MutableStateFlow(DiceUiState())
val uiState: StateFlow<DiceUiState> = _uiState.asStateFlow()
// Called from the UI
fun rollDice() {
viewModelScope.launch() {
// Other Coroutines that may be called from the current context
…
withContext(defaultDispatcher) {
_uiState.update { currentState ->
currentState.copy(
firstDieValue = SlowRandom.nextInt(from = 1, until = 7),
secondDieValue = SlowRandom.nextInt(from = 1, until = 7),
numberOfRolls = currentState.numberOfRolls + 1,
)
}
}
}
}
}
สถานะการเขียน
class DiceRollViewModel(
private val defaultDispatcher: CoroutineScope = Dispatchers.Default
) : ViewModel() {
private val _uiState = MutableDiceUiState()
val uiState: DiceUiState = _uiState
// Called from the UI
fun rollDice() {
viewModelScope.launch() {
// Other Coroutines that may be called from the current context
…
withContext(defaultDispatcher) {
Snapshot.withMutableSnapshot {
_uiState.firstDieValue = SlowRandom.nextInt(from = 1, until = 7)
_uiState.secondDieValue = SlowRandom.nextInt(from = 1, until = 7)
_uiState.numberOfRolls = _uiState.numberOfRolls + 1
}
}
}
}
}
สตรีม API เป็นแหล่งที่มาของการเปลี่ยนแปลงสถานะ
สำหรับแหล่งที่มาของการเปลี่ยนแปลงสถานะที่สร้างหลายค่าในช่วงระยะเวลาหนึ่งในสตรีม การรวมเอาต์พุตจากแหล่งข้อมูลทั้งหมด ให้เป็นหนึ่งเดียวกัน แนวทางการผลิตระดับรัฐอย่างตรงไปตรงมา
เมื่อใช้ Kotlin Flows คุณสามารถทําได้ด้วยชุดค่าผสม ตัวอย่างของการเปลี่ยนแปลงนี้สามารถดูได้ใน "ตอนนี้ใน Android" ตัวอย่างใน InterestViewModel:
class InterestsViewModel(
authorsRepository: AuthorsRepository,
topicsRepository: TopicsRepository
) : ViewModel() {
val uiState = combine(
authorsRepository.getAuthorsStream(),
topicsRepository.getTopicsStream(),
) { availableAuthors, availableTopics ->
InterestsUiState.Interests(
authors = availableAuthors,
topics = availableTopics
)
}
.stateIn(
scope = viewModelScope,
started = SharingStarted.WhileSubscribed(5_000),
initialValue = InterestsUiState.Loading
)
}
การใช้โอเปอเรเตอร์ stateIn
เพื่อสร้าง StateFlows
ช่วยให้ UI ละเอียดยิ่งขึ้น
ควบคุมกิจกรรมของไปป์ไลน์การผลิตของรัฐเนื่องจากอาจต้อง
ทำงานเฉพาะเมื่อเห็น UI
- ใช้
SharingStarted.WhileSubscribed()
หากไปป์ไลน์ควรทำงานอยู่เท่านั้น เมื่อมองเห็น UI ขณะรวบรวมโฟลว์แบบรับรู้วงจร ลักษณะ - ใช้
SharingStarted.Lazily
หากไปป์ไลน์ควรทำงานอยู่ตราบเท่าที่แอตทริบิวต์ ผู้ใช้อาจกลับไปยัง UI นั่นคือ UI อยู่ด้านหลัง หรือในอีก แท็บออกนอกหน้าจอ
ในกรณีที่ไม่มีการรวมแหล่งที่มาของรัฐที่อิงตามสตรีม ให้สตรีม API อย่าง Kotlin Flows มีการเปลี่ยนรูปแบบมากมาย เช่น การผสาน flattening และอื่นๆ เป็น ช่วยประมวลผลสตรีมให้อยู่ในสถานะ UI
ใช้ One-shot และ Stream API เป็นแหล่งที่มาของการเปลี่ยนแปลงสถานะ
ในกรณีที่ไปป์ไลน์การผลิตสถานะต้องใช้การเรียกใช้แบบครั้งเดียวทั้ง 2 แบบ และสตรีมเป็นที่มาของการเปลี่ยนแปลงสถานะ สตรีมคือข้อจำกัด ดังนั้น จึงแปลงการโทรแบบครั้งเดียวเป็นสตรีม API หรือท่อเอาต์พุตลงในสตรีมแล้วประมวลผลต่อตามที่อธิบายไว้ ในส่วนสตรีมด้านบน
เมื่อมีขั้นตอน การดำเนินการดังกล่าวมักจะหมายถึงการสร้างการสำรองข้อมูลส่วนตัวอย่างน้อย 1 รายการ
MutableStateFlow
อินสแตนซ์เพื่อเปลี่ยนแปลงสถานะการเผยแพร่ นอกจากนี้คุณยัง
สร้างโฟลว์สแนปชอตจากสถานะการเขียน
โปรดพิจารณา TaskDetailViewModel
จาก
Architecture-ตัวอย่าง ด้านล่าง
โฟลว์สถานะ
class TaskDetailViewModel @Inject constructor(
private val tasksRepository: TasksRepository,
savedStateHandle: SavedStateHandle
) : ViewModel() {
private val _isTaskDeleted = MutableStateFlow(false)
private val _task = tasksRepository.getTaskStream(taskId)
val uiState: StateFlow<TaskDetailUiState> = combine(
_isTaskDeleted,
_task
) { isTaskDeleted, task ->
TaskDetailUiState(
task = taskAsync.data,
isTaskDeleted = isTaskDeleted
)
}
// Convert the result to the appropriate observable API for the UI
.stateIn(
scope = viewModelScope,
started = SharingStarted.WhileSubscribed(5_000),
initialValue = TaskDetailUiState()
)
fun deleteTask() = viewModelScope.launch {
tasksRepository.deleteTask(taskId)
_isTaskDeleted.update { true }
}
}
สถานะการเขียน
class TaskDetailViewModel @Inject constructor(
private val tasksRepository: TasksRepository,
savedStateHandle: SavedStateHandle
) : ViewModel() {
private var _isTaskDeleted by mutableStateOf(false)
private val _task = tasksRepository.getTaskStream(taskId)
val uiState: StateFlow<TaskDetailUiState> = combine(
snapshotFlow { _isTaskDeleted },
_task
) { isTaskDeleted, task ->
TaskDetailUiState(
task = taskAsync.data,
isTaskDeleted = isTaskDeleted
)
}
// Convert the result to the appropriate observable API for the UI
.stateIn(
scope = viewModelScope,
started = SharingStarted.WhileSubscribed(5_000),
initialValue = TaskDetailUiState()
)
fun deleteTask() = viewModelScope.launch {
tasksRepository.deleteTask(taskId)
_isTaskDeleted = true
}
}
ประเภทเอาต์พุตในไปป์ไลน์การผลิตสถานะ
ตัวเลือก API เอาต์พุตสำหรับสถานะ UI และลักษณะการนำเสนอ ส่วนใหญ่แล้วจะขึ้นอยู่กับ API ที่แอปใช้ในการแสดงผล UI ในแอป Android คุณ สามารถเลือกใช้ View หรือ Jetpack Compose ได้ ข้อควรพิจารณามีดังนี้
- สถานะการอ่านในลักษณะการรับรู้วงจร
- สถานะควรเปิดเผยในช่องเดียวหรือหลายช่องจาก ตัวเก็บสถานะ
ตารางต่อไปนี้สรุป API ที่จะใช้สําหรับเวอร์ชันที่ใช้งานจริงของรัฐ ไปป์ไลน์สําหรับอินพุตและผู้บริโภคที่ระบุ
อินพุต | ผู้บริโภค | เอาต์พุต |
---|---|---|
API แบบ One-shot | ยอดดู | StateFlow หรือ LiveData |
API แบบ One-shot | เขียน | StateFlow หรือเขียน State |
API ของสตรีม | ยอดดู | StateFlow หรือ LiveData |
API ของสตรีม | เขียน | StateFlow |
API แบบ One-shot and Stream API | ยอดดู | StateFlow หรือ LiveData |
API แบบ One-shot and Stream API | เขียน | StateFlow |
การเริ่มต้นไปป์ไลน์การผลิตสถานะ
การเริ่มต้นไปป์ไลน์การผลิตสถานะเกี่ยวข้องกับการตั้งค่าเงื่อนไขเริ่มต้น
เพื่อให้ไปป์ไลน์ทำงาน ซึ่งอาจรวมถึงการระบุค่าอินพุตเริ่มต้น
ที่สำคัญต่อการเริ่มต้นไปป์ไลน์ เช่น id
สำหรับพร็อพเพอร์ตี้
มุมมองรายละเอียดของบทความข่าว หรือการเริ่มโหลดแบบไม่พร้อมกัน
คุณควรเริ่มต้นไปป์ไลน์การผลิตสถานะแบบ Lazy Loading หากเป็นไปได้
เพื่อประหยัดทรัพยากรของระบบ
ซึ่งในทางปฏิบัติแล้ว มักจะหมายถึงการรอจนกว่าจะมีผู้บริโภคผลิตภัณฑ์
เอาต์พุต Flow
API อนุญาตการดำเนินการนี้ด้วย
อาร์กิวเมนต์ started
ใน stateIn
ในกรณีที่ไม่เกี่ยวข้อง
กำหนด idempotent
initialize()
เพื่อเริ่มไปป์ไลน์การผลิตสถานะอย่างชัดแจ้ง
ดังที่แสดงในข้อมูลโค้ดต่อไปนี้
class MyViewModel : ViewModel() {
private var initializeCalled = false
// This function is idempotent provided it is only called from the UI thread.
@MainThread
fun initialize() {
if(initializeCalled) return
initializeCalled = true
viewModelScope.launch {
// seed the state production pipeline
}
}
}
ตัวอย่าง
ตัวอย่าง Google ต่อไปนี้สาธิตการสร้างรัฐใน เลเยอร์ UI ศึกษาคู่มือเพื่อดูคำแนะนำนี้ในสถานการณ์จริง
แนะนำสำหรับคุณ
- หมายเหตุ: ข้อความลิงก์จะแสดงเมื่อ JavaScript ปิดอยู่
- เลเยอร์ UI
- สร้างแอปที่ใช้แบบออฟไลน์เป็นหลัก
- เจ้าของสถานะและสถานะ UI {:#mad-Arc}