Skip to content
This repository has been archived by the owner on Jul 16, 2024. It is now read-only.

Migrate LiveData to Flow #68

Merged
merged 12 commits into from
Apr 8, 2022
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ package io.goooler.demoapp.detail.ui
import android.os.Bundle
import androidx.activity.compose.setContent
import androidx.activity.viewModels
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.livedata.observeAsState
import io.goooler.demoapp.base.core.BaseActivity
import io.goooler.demoapp.detail.vm.DetailViewModel

Expand All @@ -21,9 +21,8 @@ class RepoDetailActivity : BaseActivity() {
}

setContent {
val model = vm.repoDetailModel.observeAsState().value
?: throw IllegalArgumentException("RepoDetailModel has not been initialized")
val isRefreshing by vm.isRefreshing.observeAsState(false)
val model by vm.repoDetailModel.collectAsState()
val isRefreshing by vm.isRefreshing.collectAsState()
DetailPageWithSwipeRefresh(isRefreshing, vm::refresh, model, vm::fork)
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,28 +1,33 @@
package io.goooler.demoapp.detail.vm

import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope
import io.goooler.demoapp.base.core.BaseViewModel
import io.goooler.demoapp.base.util.MutableBooleanLiveData
import io.goooler.demoapp.common.network.RetrofitHelper
import io.goooler.demoapp.detail.model.RepoDetailModel
import io.goooler.demoapp.detail.repository.DetailRepository
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch

class DetailViewModel : BaseViewModel() {

private val repository = DetailRepository(RetrofitHelper.create())
private var repoDetail = RepoDetailModel()
private val _repoDetailModel = MutableLiveData(repoDetail)

private val _repoDetailModel = MutableStateFlow(repoDetail)
private val _isRefreshing = MutableStateFlow(false)

lateinit var fullName: String
val repoDetailModel: LiveData<RepoDetailModel> = _repoDetailModel
val isRefreshing: MutableBooleanLiveData = MutableBooleanLiveData()

val repoDetailModel: StateFlow<RepoDetailModel>
get() = _repoDetailModel.asStateFlow()
val isRefreshing: StateFlow<Boolean>
get() = _isRefreshing.asStateFlow()
Comment on lines +22 to +26
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Follow up #57 (comment).


fun refresh() {
isRefreshing.value = true
viewModelScope.launch {
_isRefreshing.emit(true)
repository.getRepoDetail(fullName).let {
repoDetail = RepoDetailModel(
it.fullName,
Expand All @@ -34,7 +39,7 @@ class DetailViewModel : BaseViewModel() {
)
}
_repoDetailModel.value = repoDetail
isRefreshing.value = false
_isRefreshing.emit(false)
}
}

Expand Down
82 changes: 42 additions & 40 deletions main/src/main/kotlin/io/goooler/demoapp/main/vm/MainSrlViewModel.kt
Original file line number Diff line number Diff line change
@@ -1,35 +1,37 @@
package io.goooler.demoapp.main.vm

import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel
import io.goooler.demoapp.base.util.MutableBooleanLiveData
import io.goooler.demoapp.base.util.MutableListLiveData
import io.goooler.demoapp.common.base.theme.BaseRxViewModel
import io.goooler.demoapp.common.base.theme.BaseThemeViewModel
import io.goooler.demoapp.common.type.CommonConstants
import io.goooler.demoapp.main.model.MainCommonVhModel
import io.goooler.demoapp.main.repository.MainCommonRepository
import java.util.Collections
import javax.inject.Inject
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.launch

@HiltViewModel
class MainSrlViewModel @Inject constructor(private val repository: MainCommonRepository) :
BaseRxViewModel() {
BaseThemeViewModel() {

private val _listData = mutableListOf<MainCommonVhModel>()
private var page = 1

val listData = MutableListLiveData<MainCommonVhModel>()
val isLoadMoreFinish = MutableBooleanLiveData()
val isRefreshFinish = MutableBooleanLiveData()
val isNoMore = MutableBooleanLiveData()
val isEnableRefresh = MutableBooleanLiveData()
val isEnableLoadMore = MutableBooleanLiveData()
val listData: MutableStateFlow<List<MainCommonVhModel>> = MutableStateFlow(emptyList())
val isLoadMoreFinish = MutableStateFlow(false)
val isRefreshFinish = MutableStateFlow(false)
val isNoMore = MutableStateFlow(false)
val isEnableRefresh = MutableStateFlow(false)
val isEnableLoadMore = MutableStateFlow(false)

init {
enableRefreshAndLoadMore(true)
}

fun refresh() {
page = 1
isNoMore.value = false
_listData.clear()
fetchListData(page)
}
Expand All @@ -50,39 +52,39 @@ class MainSrlViewModel @Inject constructor(private val repository: MainCommonRep
}

private fun fetchListData(page: Int) {
repository.getRepoListWithRx("goooler", page)
.doFinally {
isRefreshFinish.postValue(true)
isLoadMoreFinish.postValue(true)
viewModelScope.launch {
try {
finishRefreshAndLoadMore(false)
repository.getRepoListWithCr("goooler", page)
.map { bean ->
MainCommonVhModel.Repo(bean.owner?.avatarUrl, bean.name, bean.fullName)
}.let {
_listData += it
if (page == 1 && it.isEmpty()) {
_listData += listOf(MainCommonVhModel.Empty())
}
if (it.size < CommonConstants.DEFAULT_PAGE_SIZE) {
isNoMore.value = true
}
}.let {
listData.value = _listData.toList()
}
} catch (_: Exception) {
listData.value = listOf(MainCommonVhModel.Error())
enableRefreshAndLoadMore(false)
} finally {
finishRefreshAndLoadMore(true)
}
.map {
it.map { bean ->
MainCommonVhModel.Repo(bean.owner?.avatarUrl, bean.name, bean.fullName)
}
}
.doOnSuccess {
_listData += it
if (page == 1 && it.isEmpty()) {
_listData += listOf(MainCommonVhModel.Empty())
}
if (it.size < CommonConstants.DEFAULT_PAGE_SIZE) {
isNoMore.postValue(true)
}
}
.subscribe(
{
listData.postValue(_listData)
},
{
listData.postValue(listOf(MainCommonVhModel.Error()))
enableRefreshAndLoadMore(false)
}
)
.autoDispose()
}
}

private fun finishRefreshAndLoadMore(finish: Boolean) {
isRefreshFinish.value = finish
isLoadMoreFinish.value = finish
}

private fun enableRefreshAndLoadMore(enable: Boolean) {
isEnableRefresh.postValue(enable)
isEnableLoadMore.postValue(enable)
isEnableRefresh.value = enable
isEnableLoadMore.value = enable
}
}