简体   繁体   中英

init { } block in Android ViewModel is repeatedly called and collects flow when app is brought to the foreground

In my Android app, with Kotlin and using Koin dependency injection, my init block is repeatedly called every time the app is brought into the foreground. The issue this causes is making additional background calls that are not necessary when the app is brought into the foreground, and the View refreshes when I don't always want it too. My question is, how to properly utilize the init block and collect a single flow without the init block methods being repeatedly called ? Is init { } always called when a ViewModel is brought into the foreground?

Below is an example of how I'm utilizing the ViewModel in my fragment, and the methods called in my init block:

import org.koin.androidx.viewmodel.ext.android.*

class MyFragment: Fragment() {

     private val viewModel: MyViewModel by viewModel()

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

         collectSomeFlow()
     }

     private fun collectSomeFlow() {
          lifecycleScope.launchWhenStarted {
            viewModel.onUiStateChanged.collect {
                 // do something here
            }
        }
     }

}

class MyViewModel: ViewModel(private val repository: MyRepository): ViewModel() {

     private val _uiState: MutableStateFlow<MyUiState> = MutableStateFlow(MyUiState.Success(emptyList()))
     val uiState: StateFlow<MyUiState> = _uiState


     init {
         // Repeatedly fired off after View is created if app is resumed again
         getSomeDataFromNetwork()
     }
    
     private fun getSomeDataFromNetwork() {
          viewModelScope.launch {
               val response = repository.getSomeDataFromNetwork()
               // Handle response, update _uiState, etc.
          }
     }

}

Hi seems there is no strange thing running, However, you call request every time when Lifecycle event is in started state You can simply change the collectSomeFlow function

private fun collectSomeFlow() {
      lifecycleScope.launchWhenStarted {
        viewModel.onUiStateChanged.collect {
             // do something here
        }
    }
 }

to

private fun collectSomeFlow() {
      lifecycleScope.launchWhenCreated {
        viewModel.onUiStateChanged.collect {
             // do something here
        }
    }
 }

launchWhenCreated Launches and runs the given block when the Lifecycle controlling this LifecycleCoroutineScope is at least in Lifecycle.State.CREATED state.

https://developer.android.com/reference/kotlin/androidx/lifecycle/LifecycleCoroutineScope

you should use:

  lifecycleScope.launch {
            yourFlow.flowWithLifecycle(this@MyFragment.viewLifecycleOwner.lifecycle, Lifecycle.State.CREATED).collect {
                //collect
            }
        }

or just use an extension function for clean code:

//With Activities:

fun <T> AppCompatActivity.launchAndRepeatWithLifecycleNotNull(
    flow: Flow<T?>,
    minActiveState: Lifecycle.State = Lifecycle.State.STARTED,
    block: (T) -> Unit
) {
    lifecycleScope.launch {
        flow.flowWithLifecycle(this@launchAndRepeatWithLifecycleNotNull.lifecycle, minActiveState).collect {
            it?.let(block)
        }
    }
} 

//With Fragments:

fun <T> Fragment.launchAndRepeatWithViewLifecycleNotNull(
    flow: Flow<T?>,
    minActiveState: Lifecycle.State = Lifecycle.State.STARTED,
    block: (T) -> Unit
) {
    viewLifecycleOwner.lifecycleScope.launch {
        flow.flowWithLifecycle(this@launchAndRepeatWithViewLifecycleNotNull.viewLifecycleOwner.lifecycle, minActiveState).collect {
            it?.let(block)
        }
    }
}

Usage:

    launchAndRepeatWithLifecycleNotNull(yourFlow, OnWhichStateTheFlowShouldCollect) {
         //collect flow
    }
//OnWhichStateTheFlowShouldCollect on your case is CREATED

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM