Skip to content

Commit

Permalink
Move lifecycle logic to base classes
Browse files Browse the repository at this point in the history
  • Loading branch information
hichamboushaba committed Oct 30, 2021
1 parent 58f77f2 commit 346d0f9
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 33 deletions.
16 changes: 16 additions & 0 deletions app/src/main/java/com/hicham/flowlifecycle/BaseFragment.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.hicham.flowlifecycle

import android.os.Bundle
import android.view.View
import androidx.annotation.LayoutRes
import androidx.fragment.app.Fragment

abstract class BaseFragment<T : BaseViewModel>(@LayoutRes contentLayoutId: Int) :
Fragment(contentLayoutId) {
protected abstract val viewModel: T

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewModel.startObservingLifecycle(viewLifecycleOwner)
}
}
37 changes: 37 additions & 0 deletions app/src/main/java/com/hicham/flowlifecycle/BaseViewModel.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package com.hicham.flowlifecycle

import android.app.Application
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleEventObserver
import androidx.lifecycle.LifecycleOwner
import kotlinx.coroutines.channels.BufferOverflow
import kotlinx.coroutines.flow.*

open class BaseViewModel(application: Application): AndroidViewModel(application) {
private val lifeCycleState = MutableSharedFlow<Lifecycle.State>(
replay = 1,
onBufferOverflow = BufferOverflow.DROP_OLDEST
)

private val lifecycleObserver = object : LifecycleEventObserver {
override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
lifeCycleState.tryEmit(source.lifecycle.currentState)
if (source.lifecycle.currentState == Lifecycle.State.DESTROYED) {
source.lifecycle.removeObserver(this)
}
}
}

fun startObservingLifecycle(lifecycleOwner: LifecycleOwner) {
lifecycleOwner.lifecycle.addObserver(lifecycleObserver)
}

protected fun <T> Flow<T>.whenAtLeast(requiredState: Lifecycle.State): Flow<T> {
return lifeCycleState.map { state -> state.isAtLeast(requiredState) }
.distinctUntilChanged()
.flatMapLatest {
if (it) this else emptyFlow()
}
}
}
8 changes: 2 additions & 6 deletions app/src/main/java/com/hicham/flowlifecycle/MainFragment.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,14 @@ import android.os.Bundle
import android.view.View
import androidx.activity.result.contract.ActivityResultContracts
import androidx.core.view.isVisible
import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
import androidx.lifecycle.lifecycleScope
import com.hicham.flowlifecycle.databinding.FragmentMainBinding
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach

class MainFragment : Fragment(R.layout.fragment_main) {
private val viewModel: MainViewModel by viewModels()
class MainFragment : BaseFragment<MainViewModel>(R.layout.fragment_main) {
override val viewModel: MainViewModel by viewModels()

private val requestPermissionLauncher =
registerForActivityResult(
Expand All @@ -29,13 +28,10 @@ class MainFragment : Fragment(R.layout.fragment_main) {

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewModel.startObservingLifecycle(viewLifecycleOwner)

val binding = FragmentMainBinding.bind(view)

val hasLocationPermission =
requireContext().checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) == PERMISSION_GRANTED

if (hasLocationPermission) {
viewModel.onLocationPermissionGranted()
} else {
Expand Down
28 changes: 1 addition & 27 deletions app/src/main/java/com/hicham/flowlifecycle/MainViewModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,26 +6,12 @@ import androidx.lifecycle.*
import kotlinx.coroutines.channels.BufferOverflow
import kotlinx.coroutines.flow.*

class MainViewModel(application: Application) : AndroidViewModel(application) {
class MainViewModel(application: Application) : BaseViewModel(application) {
private val locationObserver = LocationObserver(application)
private val api: FakeApi = FakeApi()

private val hasLocationPermission = MutableStateFlow(false)

private val lifeCycleState = MutableSharedFlow<Lifecycle.State>(
replay = 1,
onBufferOverflow = BufferOverflow.DROP_OLDEST
)

private val lifecycleObserver = object : LifecycleEventObserver {
override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
lifeCycleState.tryEmit(source.lifecycle.currentState)
if (source.lifecycle.currentState == Lifecycle.State.DESTROYED) {
source.lifecycle.removeObserver(this)
}
}
}

private val locationUpdates: Flow<Location> = hasLocationPermission
.filter { it }
.flatMapLatest { locationObserver.observeLocationUpdates() }
Expand All @@ -50,18 +36,6 @@ class MainViewModel(application: Application) : AndroidViewModel(application) {
fun onLocationPermissionGranted() {
hasLocationPermission.value = true
}

fun startObservingLifecycle(lifecycleOwner: LifecycleOwner) {
lifecycleOwner.lifecycle.addObserver(lifecycleObserver)
}

private fun <T> Flow<T>.whenAtLeast(requiredState: Lifecycle.State): Flow<T> {
return lifeCycleState.map { state -> state.isAtLeast(requiredState) }
.distinctUntilChanged()
.flatMapLatest {
if (it) this else emptyFlow()
}
}
}

data class ViewState(
Expand Down

0 comments on commit 346d0f9

Please sign in to comment.