Skip to content

Commit 884c726

Browse files
committed
change liveData to stateFlow
1 parent b43944f commit 884c726

File tree

16 files changed

+122
-136
lines changed

16 files changed

+122
-136
lines changed

app/src/main/java/com/example/moviedb/compose/ui/home/HomeScreen.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,8 @@ fun HomeScreen(
4141
navController: NavController,
4242
viewModel: PopularMovieViewModel = hiltViewModel()
4343
) {
44-
val movieList by viewModel.itemList.observeAsState(listOf())
45-
val refreshing by viewModel.isRefreshing.observeAsState(false)
44+
val movieList by viewModel.itemList.collectAsState(listOf())
45+
val refreshing by viewModel.isRefreshing.collectAsState(false)
4646
val pullRefreshState = rememberPullRefreshState(refreshing, { viewModel.doRefresh() })
4747
val scrollState = rememberLazyGridState()
4848
val endOfListReached by remember {

app/src/main/java/com/example/moviedb/ui/base/BaseActivity.kt

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,14 @@ import androidx.annotation.LayoutRes
55
import androidx.appcompat.app.AppCompatActivity
66
import androidx.databinding.DataBindingUtil
77
import androidx.databinding.ViewDataBinding
8+
import androidx.lifecycle.lifecycleScope
89
import com.example.moviedb.BR
910
import com.example.moviedb.R
1011
import com.example.moviedb.utils.dismissLLoadingDialog
1112
import com.example.moviedb.utils.showDialog
1213
import com.example.moviedb.utils.showLoadingDialog
14+
import kotlinx.coroutines.flow.collectLatest
15+
import kotlinx.coroutines.launch
1316

1417
abstract class BaseActivity<ViewBinding : ViewDataBinding, ViewModel : BaseViewModel> :
1518
AppCompatActivity() {
@@ -33,26 +36,26 @@ abstract class BaseActivity<ViewBinding : ViewDataBinding, ViewModel : BaseViewM
3336
}
3437

3538
private fun observeErrorEvent() {
36-
viewModel.apply {
37-
isLoading.observe(this@BaseActivity) {
38-
handleLoading(it == true)
39+
lifecycleScope.launch {
40+
viewModel.isLoading.collectLatest {
41+
handleLoading(it)
3942
}
40-
errorMessage.observe(this@BaseActivity) {
43+
viewModel.errorMessage.collectLatest {
4144
handleErrorMessage(it)
4245
}
43-
noInternetConnectionEvent.observe(this@BaseActivity) {
46+
viewModel.noInternetConnectionEvent.collectLatest {
4447
handleErrorMessage(getString(R.string.no_internet_connection))
4548
}
46-
connectTimeoutEvent.observe(this@BaseActivity) {
49+
viewModel.connectTimeoutEvent.collectLatest {
4750
handleErrorMessage(getString(R.string.connect_timeout))
4851
}
49-
forceUpdateAppEvent.observe(this@BaseActivity) {
52+
viewModel.forceUpdateAppEvent.collectLatest {
5053
handleErrorMessage(getString(R.string.force_update_app))
5154
}
52-
serverMaintainEvent.observe(this@BaseActivity) {
55+
viewModel.serverMaintainEvent.collectLatest {
5356
handleErrorMessage(getString(R.string.server_maintain_message))
5457
}
55-
unknownErrorEvent.observe(this@BaseActivity) {
58+
viewModel.unknownErrorEvent.collectLatest {
5659
handleErrorMessage(getString(R.string.unknown_error))
5760
}
5861
}

app/src/main/java/com/example/moviedb/ui/base/BaseBottomSheetDialogFragment.kt

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,15 @@ import androidx.databinding.ViewDataBinding
1010
import androidx.fragment.app.DialogFragment
1111
import androidx.fragment.app.Fragment
1212
import androidx.fragment.app.FragmentTransaction
13+
import androidx.lifecycle.lifecycleScope
1314
import com.example.moviedb.BR
1415
import com.example.moviedb.R
1516
import com.example.moviedb.utils.dismissLLoadingDialog
1617
import com.example.moviedb.utils.showDialog
1718
import com.example.moviedb.utils.showLoadingDialog
1819
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
20+
import kotlinx.coroutines.flow.collectLatest
21+
import kotlinx.coroutines.launch
1922

2023
abstract class BaseBottomSheetDialogFragment<ViewBinding : ViewDataBinding, ViewModel : BaseViewModel> :
2124
BottomSheetDialogFragment() {
@@ -47,26 +50,26 @@ abstract class BaseBottomSheetDialogFragment<ViewBinding : ViewDataBinding, View
4750
}
4851

4952
private fun observerEvents() {
50-
viewModel.apply {
51-
isLoading.observe(viewLifecycleOwner) {
52-
handleLoading(it == true)
53+
lifecycleScope.launch {
54+
viewModel.isLoading.collectLatest {
55+
handleLoading(it)
5356
}
54-
errorMessage.observe(viewLifecycleOwner) {
57+
viewModel.errorMessage.collectLatest {
5558
handleErrorMessage(it)
5659
}
57-
noInternetConnectionEvent.observe(viewLifecycleOwner) {
60+
viewModel.noInternetConnectionEvent.collectLatest {
5861
handleErrorMessage(getString(R.string.no_internet_connection))
5962
}
60-
connectTimeoutEvent.observe(viewLifecycleOwner) {
63+
viewModel.connectTimeoutEvent.collectLatest {
6164
handleErrorMessage(getString(R.string.connect_timeout))
6265
}
63-
forceUpdateAppEvent.observe(viewLifecycleOwner) {
66+
viewModel.forceUpdateAppEvent.collectLatest {
6467
handleErrorMessage(getString(R.string.force_update_app))
6568
}
66-
serverMaintainEvent.observe(viewLifecycleOwner) {
69+
viewModel.serverMaintainEvent.collectLatest {
6770
handleErrorMessage(getString(R.string.server_maintain_message))
6871
}
69-
unknownErrorEvent.observe(viewLifecycleOwner) {
72+
viewModel.unknownErrorEvent.collectLatest {
7073
handleErrorMessage(getString(R.string.unknown_error))
7174
}
7275
}

app/src/main/java/com/example/moviedb/ui/base/BaseDialogFragment.kt

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,14 @@ import androidx.databinding.ViewDataBinding
1010
import androidx.fragment.app.DialogFragment
1111
import androidx.fragment.app.Fragment
1212
import androidx.fragment.app.FragmentTransaction
13+
import androidx.lifecycle.lifecycleScope
1314
import com.example.moviedb.BR
1415
import com.example.moviedb.R
1516
import com.example.moviedb.utils.dismissLLoadingDialog
1617
import com.example.moviedb.utils.showDialog
1718
import com.example.moviedb.utils.showLoadingDialog
19+
import kotlinx.coroutines.flow.collectLatest
20+
import kotlinx.coroutines.launch
1821

1922
abstract class BaseDialogFragment<ViewBinding : ViewDataBinding, ViewModel : BaseViewModel> :
2023
DialogFragment() {
@@ -46,26 +49,26 @@ abstract class BaseDialogFragment<ViewBinding : ViewDataBinding, ViewModel : Bas
4649
}
4750

4851
private fun observerEvents() {
49-
viewModel.apply {
50-
isLoading.observe(viewLifecycleOwner) {
51-
handleLoading(it == true)
52+
lifecycleScope.launch {
53+
viewModel.isLoading.collectLatest {
54+
handleLoading(it)
5255
}
53-
errorMessage.observe(viewLifecycleOwner) {
56+
viewModel.errorMessage.collectLatest {
5457
handleErrorMessage(it)
5558
}
56-
noInternetConnectionEvent.observe(viewLifecycleOwner) {
59+
viewModel.noInternetConnectionEvent.collectLatest {
5760
handleErrorMessage(getString(R.string.no_internet_connection))
5861
}
59-
connectTimeoutEvent.observe(viewLifecycleOwner) {
62+
viewModel.connectTimeoutEvent.collectLatest {
6063
handleErrorMessage(getString(R.string.connect_timeout))
6164
}
62-
forceUpdateAppEvent.observe(viewLifecycleOwner) {
65+
viewModel.forceUpdateAppEvent.collectLatest {
6366
handleErrorMessage(getString(R.string.force_update_app))
6467
}
65-
serverMaintainEvent.observe(viewLifecycleOwner) {
68+
viewModel.serverMaintainEvent.collectLatest {
6669
handleErrorMessage(getString(R.string.server_maintain_message))
6770
}
68-
unknownErrorEvent.observe(viewLifecycleOwner) {
71+
viewModel.unknownErrorEvent.collectLatest {
6972
handleErrorMessage(getString(R.string.unknown_error))
7073
}
7174
}

app/src/main/java/com/example/moviedb/ui/base/BaseFragment.kt

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,16 @@ import androidx.databinding.ViewDataBinding
1010
import androidx.fragment.app.DialogFragment
1111
import androidx.fragment.app.Fragment
1212
import androidx.fragment.app.FragmentTransaction
13+
import androidx.lifecycle.lifecycleScope
1314
import androidx.navigation.NavController
1415
import androidx.navigation.fragment.NavHostFragment
1516
import com.example.moviedb.BR
1617
import com.example.moviedb.R
1718
import com.example.moviedb.utils.dismissLLoadingDialog
1819
import com.example.moviedb.utils.showDialog
1920
import com.example.moviedb.utils.showLoadingDialog
21+
import kotlinx.coroutines.flow.collectLatest
22+
import kotlinx.coroutines.launch
2023

2124
abstract class BaseFragment<ViewBinding : ViewDataBinding, ViewModel : BaseViewModel> : Fragment() {
2225

@@ -47,26 +50,26 @@ abstract class BaseFragment<ViewBinding : ViewDataBinding, ViewModel : BaseViewM
4750
}
4851

4952
private fun observerEvents() {
50-
viewModel.apply {
51-
isLoading.observe(viewLifecycleOwner) {
52-
handleLoading(it == true)
53+
lifecycleScope.launch {
54+
viewModel.isLoading.collectLatest {
55+
handleLoading(it)
5356
}
54-
errorMessage.observe(viewLifecycleOwner) {
57+
viewModel.errorMessage.collectLatest {
5558
handleErrorMessage(it)
5659
}
57-
noInternetConnectionEvent.observe(viewLifecycleOwner) {
60+
viewModel.noInternetConnectionEvent.collectLatest {
5861
handleErrorMessage(getString(R.string.no_internet_connection))
5962
}
60-
connectTimeoutEvent.observe(viewLifecycleOwner) {
63+
viewModel.connectTimeoutEvent.collectLatest {
6164
handleErrorMessage(getString(R.string.connect_timeout))
6265
}
63-
forceUpdateAppEvent.observe(viewLifecycleOwner) {
66+
viewModel.forceUpdateAppEvent.collectLatest {
6467
handleErrorMessage(getString(R.string.force_update_app))
6568
}
66-
serverMaintainEvent.observe(viewLifecycleOwner) {
69+
viewModel.serverMaintainEvent.collectLatest {
6770
handleErrorMessage(getString(R.string.server_maintain_message))
6871
}
69-
unknownErrorEvent.observe(viewLifecycleOwner) {
72+
viewModel.unknownErrorEvent.collectLatest {
7073
handleErrorMessage(getString(R.string.unknown_error))
7174
}
7275
}

app/src/main/java/com/example/moviedb/ui/base/BaseViewModel.kt

Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@ package com.example.moviedb.ui.base
33
import androidx.lifecycle.ViewModel
44
import androidx.lifecycle.viewModelScope
55
import com.example.moviedb.data.remote.toBaseException
6-
import com.example.moviedb.utils.SingleLiveData
76
import kotlinx.coroutines.CoroutineExceptionHandler
7+
import kotlinx.coroutines.flow.MutableSharedFlow
8+
import kotlinx.coroutines.flow.MutableStateFlow
89
import kotlinx.coroutines.launch
910
import kotlinx.coroutines.plus
1011
import java.net.ConnectException
@@ -15,17 +16,17 @@ import java.net.UnknownHostException
1516
open class BaseViewModel : ViewModel() {
1617

1718
// loading flag
18-
val isLoading by lazy { SingleLiveData<Boolean>().apply { value = false } }
19+
val isLoading by lazy { MutableStateFlow(false) }
1920

2021
// error message
21-
val errorMessage by lazy { SingleLiveData<String>() }
22+
val errorMessage by lazy { MutableSharedFlow<String>() }
2223

2324
// optional flags
24-
val noInternetConnectionEvent by lazy { SingleLiveData<Unit>() }
25-
val connectTimeoutEvent by lazy { SingleLiveData<Unit>() }
26-
val forceUpdateAppEvent by lazy { SingleLiveData<Unit>() }
27-
val serverMaintainEvent by lazy { SingleLiveData<Unit>() }
28-
val unknownErrorEvent by lazy { SingleLiveData<Unit>() }
25+
val noInternetConnectionEvent by lazy { MutableSharedFlow<Unit>() }
26+
val connectTimeoutEvent by lazy { MutableSharedFlow<Unit>() }
27+
val forceUpdateAppEvent by lazy { MutableSharedFlow<Unit>() }
28+
val serverMaintainEvent by lazy { MutableSharedFlow<Unit>() }
29+
val unknownErrorEvent by lazy { MutableSharedFlow<Unit>() }
2930

3031
// exception handler for coroutine
3132
private val exceptionHandler by lazy {
@@ -40,40 +41,44 @@ open class BaseViewModel : ViewModel() {
4041
/**
4142
* handle throwable when load fail
4243
*/
43-
protected open fun onError(throwable: Throwable) {
44+
protected open suspend fun onError(throwable: Throwable) {
4445
when (throwable) {
4546
// case no internet connection
4647
is UnknownHostException -> {
47-
noInternetConnectionEvent.call()
48+
noInternetConnectionEvent.emit(Unit)
4849
}
50+
4951
is ConnectException -> {
50-
noInternetConnectionEvent.call()
52+
noInternetConnectionEvent.emit(Unit)
5153
}
5254
// case request time out
5355
is SocketTimeoutException -> {
54-
connectTimeoutEvent.call()
56+
connectTimeoutEvent.emit(Unit)
5557
}
58+
5659
else -> {
5760
// convert throwable to base exception to get error information
5861
val baseException = throwable.toBaseException()
5962
when (baseException.httpCode) {
6063
HttpURLConnection.HTTP_UNAUTHORIZED -> {
61-
errorMessage.value = baseException.message
64+
errorMessage.emit(baseException.message ?: "")
6265
}
66+
6367
HttpURLConnection.HTTP_INTERNAL_ERROR -> {
64-
errorMessage.value = baseException.message
68+
errorMessage.emit(baseException.message ?: "")
6569
}
70+
6671
else -> {
67-
unknownErrorEvent.call()
72+
unknownErrorEvent.emit(Unit)
6873
}
6974
}
7075
}
7176
}
7277
hideLoading()
7378
}
7479

75-
open fun showError(e: Throwable) {
76-
errorMessage.value = e.message
80+
open suspend fun showError(e: Throwable) {
81+
errorMessage.emit(e.message ?: "")
7782
}
7883

7984
fun showLoading() {

app/src/main/java/com/example/moviedb/ui/base/loadmorerefresh/BaseLoadMoreRefreshFragment.kt

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,15 @@ package com.example.moviedb.ui.base.loadmorerefresh
33
import android.os.Bundle
44
import android.view.View
55
import androidx.databinding.ViewDataBinding
6+
import androidx.lifecycle.lifecycleScope
67
import androidx.recyclerview.widget.LinearLayoutManager
78
import androidx.recyclerview.widget.RecyclerView
89
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
910
import com.example.moviedb.R
1011
import com.example.moviedb.ui.base.BaseFragment
1112
import com.example.moviedb.ui.base.BaseListAdapter
13+
import kotlinx.coroutines.flow.collectLatest
14+
import kotlinx.coroutines.launch
1215

1316
/**
1417
* should use paging 3
@@ -39,11 +42,11 @@ abstract class BaseLoadMoreRefreshFragment<ViewBinding : ViewDataBinding, ViewMo
3942
recyclerView?.layoutManager = getLayoutManager()
4043
recyclerView?.adapter = listAdapter
4144
recyclerView?.setHasFixedSize(true)
42-
viewModel.apply {
43-
itemList.observe(viewLifecycleOwner) {
45+
lifecycleScope.launch {
46+
viewModel.itemList.collectLatest {
4447
listAdapter.submitList(it)
4548
}
46-
firstLoad()
49+
viewModel.firstLoad()
4750
}
4851
}
4952

0 commit comments

Comments
 (0)