问题
I have injected sharedPreference
in ViewModel
.
Can I use android specific resource's while embedding Coroutine scope which automatically suspended when ViewModel loses scope.
I mean is it ok to use preferende in ViewModel if we add a viewModel launch scope
A CoroutineScope keeps track of all coroutines it creates. Therefore, if you cancel a scope, you cancel all coroutines it created
@ContributesViewModel
class SplashViewModel @Inject constructor(private val prefs: PrefStore) : BaseViewModel() {
val onMoveToNext = ClassLiveData()
init {
scope.launch {
val activity = if(prefs.isLoggedIn()) HomeActivity::class
else OnBoardingActivity::class
onMoveToNext.postValue(activity)
}
}
///fun saveDeviceID(id:String) = prefs.setDeviceID(id)
//fun createErrorCodeHash() ={}
fun getIsLoggedIn():Boolean = prefs.isLoggedIn()
fun setSecondTimeLogin(boolean: Boolean) = prefs.setIsSecondTimeLogin(boolean)
}
Where
abstract class BaseViewModel: ViewModel() {
private val job = Job()
val scope = CoroutineScope(Dispatchers.IO + job)
override fun onCleared() {
super.onCleared()
job.cancel()
}
}
where ClassLiveData
typealias ClassLiveData = MutableLiveData<KClass<*>>
And called it in SplashActivity
viewModel.onMoveToNext.listen(this) {
Handler().postDelayed({
val intent = Intent(this, it.java)
intent.putExtra("Role", "LOGIN")
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK)
startActivity(intent)
}, 2000)
回答1:
As a general rule of thumb, when it comes to keeping a reference to context
or other objects that have hard references on context
(e.g. ContextWrapper
, which is where SharedPrefferences
are coming from), one should treat coroutines the same as classic threads.
For example, a live coroutine with Dispathers.IO
potentially can leak the context
in the same way as a classic thread
, AsyncTasks
, etc. Therefore, managing these references and cleaning them up is the developers' responsibility.
Looking back at your code, your base ViewModel
is working on IO
scope, which means any empty-constructor luanch
es, create a child scope on the same Dispatcher
, i.e IO
. However because of your ViewModel.onCleared()
:
override fun onCleared() {
super.onCleared()
job.cancel()
}
you are pretty much safe.
Why am I saying "pretty much"?
Because it depends on how you implement your launch
es. Remember that only canceling a job
doesn't necessarily mean that the corresponding coroutine is close and every reference is removed. Certain implementations need you directly check the state of your job inside the scope and do manual cleanups:
For instance, if you create a while loop inside a coroutine, job.cancel()
does not break it, you need to break
it manually.
Looking back one last time at your code, you are not doing anything inside your launch
that requires manual cleanups. Then, we can say your current code certainly won't leak the context
.
来源:https://stackoverflow.com/questions/58536773/is-it-ok-to-use-sharedprefrence-with-coroutine-kotlin