Jetpack 使用 StateFlow 编写、获取和添加更多项目到 LazyColumn
Jetpack Compose, fetch and add more items to LazyColumn using StateFlow
我有一个 LazyColumn
可以呈现项目列表。但是,我现在想获取更多项目以添加到我的惰性列表中。我不想 re-render 已经在 LazyColumn
中呈现的项目,我只想添加新项目。
如何使用 StateFlow
执行此操作?我需要传递 page
字符串来获取下一组项目,但是如何将页面传递给 repository.getContent()
方法?
class FeedViewModel(
private val resources: Resources,
private val repository: FeedRepository
) : ViewModel() {
// I need to pass a parameter to `repository.getContent()` to get the next block of items
private val _uiState: StateFlow<UiState> = repository.getContent()
.map { content ->
UiState.Ready(content)
}.catch { cause ->
UiState.Error(cause.message ?: resources.getString(R.string.error_generic))
}.stateIn(
scope = viewModelScope,
started = SharingStarted.WhileSubscribed(stopTimeoutMillis = SUBSCRIBE_TIMEOUT_FOR_CONFIG_CHANGE),
initialValue = UiState.Loading
)
val uiState: StateFlow<UiState>
get() = _uiState
在我的 UI 中,我有这段代码来观察流程并呈现 LazyColumn
:
val lifecycleAwareUiStateFlow: Flow<UiState> = remember(viewModel.uiState, lifecycleOwner) {
viewModel.uiState.flowWithLifecycle(lifecycleOwner.lifecycle, Lifecycle.State.STARTED)
}
val uiState: UiState by lifecycleAwareUiStateFlow.collectAsState(initial = UiState.Loading)
@Composable
fun FeedLazyColumn(
posts: List<Post> = listOf(),
scrollState: LazyListState
) {
LazyColumn(
modifier = Modifier.padding(vertical = 4.dp),
state = scrollState
) {
// how to add more posts???
items(items = posts) { post ->
Card(post)
}
}
}
我知道有一个用于 Compose 的分页库,但我正在尝试实现类似的东西,除了用户负责是否加载下一个项目。
这是期望的行为:
我能够通过在发布之前将新帖子添加到旧帖子来解决这个问题。有关相关行,请参阅下面的评论。
private val _content = MutableStateFlow<Content>(Content())
private val _uiState: StateFlow<UiState> = repository.getContent()
.mapLatest { content ->
_content.value = _content.value + content // ADDED THIS
UiState.Ready(_content.value)
}.catch { cause ->
UiState.Error(cause.message ?: resources.getString(R.string.error_generic))
}.stateIn(
scope = viewModelScope,
started = SharingStarted.WhileSubscribed(stopTimeoutMillis = SUBSCRIBE_TIMEOUT_FOR_CONFIG_CHANGE),
initialValue = UiState.Loading
)
private operator fun Content.plus(content: Content): Content = Content(
posts = this.posts + content.posts,
youTubeNextPageToken = content.youTubeNextPageToken
)
class YouTubeDataSource(private val apiService: YouTubeApiService) :
RemoteDataSource<YouTubeResponse> {
private val nextPageToken = MutableStateFlow<String?>(null)
fun setNextPageToken(nextPageToken: String) {
this.nextPageToken.value = nextPageToken
}
override fun getContent(): Flow<YouTubeResponse> = flow {
// retrigger emit when nextPageToken changes
nextPageToken.collect {
emit(apiService.getYouTubeSnippets(it))
}
}
}
我有一个 LazyColumn
可以呈现项目列表。但是,我现在想获取更多项目以添加到我的惰性列表中。我不想 re-render 已经在 LazyColumn
中呈现的项目,我只想添加新项目。
如何使用 StateFlow
执行此操作?我需要传递 page
字符串来获取下一组项目,但是如何将页面传递给 repository.getContent()
方法?
class FeedViewModel(
private val resources: Resources,
private val repository: FeedRepository
) : ViewModel() {
// I need to pass a parameter to `repository.getContent()` to get the next block of items
private val _uiState: StateFlow<UiState> = repository.getContent()
.map { content ->
UiState.Ready(content)
}.catch { cause ->
UiState.Error(cause.message ?: resources.getString(R.string.error_generic))
}.stateIn(
scope = viewModelScope,
started = SharingStarted.WhileSubscribed(stopTimeoutMillis = SUBSCRIBE_TIMEOUT_FOR_CONFIG_CHANGE),
initialValue = UiState.Loading
)
val uiState: StateFlow<UiState>
get() = _uiState
在我的 UI 中,我有这段代码来观察流程并呈现 LazyColumn
:
val lifecycleAwareUiStateFlow: Flow<UiState> = remember(viewModel.uiState, lifecycleOwner) {
viewModel.uiState.flowWithLifecycle(lifecycleOwner.lifecycle, Lifecycle.State.STARTED)
}
val uiState: UiState by lifecycleAwareUiStateFlow.collectAsState(initial = UiState.Loading)
@Composable
fun FeedLazyColumn(
posts: List<Post> = listOf(),
scrollState: LazyListState
) {
LazyColumn(
modifier = Modifier.padding(vertical = 4.dp),
state = scrollState
) {
// how to add more posts???
items(items = posts) { post ->
Card(post)
}
}
}
我知道有一个用于 Compose 的分页库,但我正在尝试实现类似的东西,除了用户负责是否加载下一个项目。
这是期望的行为:
我能够通过在发布之前将新帖子添加到旧帖子来解决这个问题。有关相关行,请参阅下面的评论。
private val _content = MutableStateFlow<Content>(Content())
private val _uiState: StateFlow<UiState> = repository.getContent()
.mapLatest { content ->
_content.value = _content.value + content // ADDED THIS
UiState.Ready(_content.value)
}.catch { cause ->
UiState.Error(cause.message ?: resources.getString(R.string.error_generic))
}.stateIn(
scope = viewModelScope,
started = SharingStarted.WhileSubscribed(stopTimeoutMillis = SUBSCRIBE_TIMEOUT_FOR_CONFIG_CHANGE),
initialValue = UiState.Loading
)
private operator fun Content.plus(content: Content): Content = Content(
posts = this.posts + content.posts,
youTubeNextPageToken = content.youTubeNextPageToken
)
class YouTubeDataSource(private val apiService: YouTubeApiService) :
RemoteDataSource<YouTubeResponse> {
private val nextPageToken = MutableStateFlow<String?>(null)
fun setNextPageToken(nextPageToken: String) {
this.nextPageToken.value = nextPageToken
}
override fun getContent(): Flow<YouTubeResponse> = flow {
// retrigger emit when nextPageToken changes
nextPageToken.collect {
emit(apiService.getYouTubeSnippets(it))
}
}
}