Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it ok to use sharedPrefrence with Coroutine kotlin

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)
like image 781
Zar E Ahmer Avatar asked Oct 17 '25 11:10

Zar E Ahmer


1 Answers

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 luanches, 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 launches. 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.

like image 156
Dusk Avatar answered Oct 20 '25 00:10

Dusk



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!