• 5
name

A PHP Error was encountered

Severity: Notice

Message: Undefined index: userid

Filename: views/question.php

Line Number: 191

Backtrace:

File: /home/prodcxja/public_html/questions/application/views/question.php
Line: 191
Function: _error_handler

File: /home/prodcxja/public_html/questions/application/controllers/Questions.php
Line: 433
Function: view

File: /home/prodcxja/public_html/questions/index.php
Line: 315
Function: require_once

I have single activity app and I have SharedViewModel attached to it, its main purpose is to be used for inner communication between fragments, etc. I also use Realm as storage solution. This viewModel as well as the others viewModels extends BaseViewModel.

open class BaseViewModel(): ViewModel() {

    val  realm: Realm = Realm.getDefaultInstance()

    override fun onCleared() {
        super.onCleared()
        realm.close()
        Log.d("BVM", "realm is ${ if (realm.isClosed) "closed." else "not closed.  Opened connections: ${Realm.getLocalInstanceCount(Realm.getDefaultConfiguration()!!)}"}")
    }
}

We are all familiar with this picture enter image description here

Since SharedViewModel's lyfecycle depends on lifecycle of activity's lifecycle, onCleared() method of this viewModel will be called not after onDestroy call of activity, but when activity is finished. It is not the same thing. As a result of that, when I leave my app, one Realm connection stays open, because activity is not in the Finished state. All other viewmodels connected from fragments had called their own onCleared() methods and their Realm's connections are closed.

What is the best and cleanest way to handle this?

I have a workaround in which I call viewModel's onCleared() manually in onDestroy method of activity and it's working, but that solution is rubbish.

Thanks in advance!

    • when I leave my app, one Realm connection stays open, because activity is not in the Finished state. that's a bug in your code, considering onCleared() is called when you leave the app (finish the Activity).
      • 1
    • You should share live data across multiple fragments using shared ViewModel but for your Realm connections (Realm related objects), I would recommend to use ViewModel that's attached to each fragments individually.
      • 2
    • @JeelVankhede, you are right, but this SharedViewModel alsohas some livedata which activity uses and also other fragments.

As a matter of fact, @EpicPandaForce was right, the bug was in ViewModel's creation. I used Dagger 2 for injection of ViewModelFactory which looks like this:

@Singleton
class ViewModelFactory @Inject constructor(
        private val creators: Map<Class<out ViewModel>, @JvmSuppressWildcards Provider<ViewModel>>
) : ViewModelProvider.Factory {
    override fun <T : ViewModel> create(modelClass: Class<T>): T {
        val creator = creators[modelClass] ?: creators.entries.firstOrNull {
            modelClass.isAssignableFrom(it.key)
        }?.value ?: throw IllegalArgumentException("unknown model class $modelClass")
        try {
            @Suppress("UNCHECKED_CAST")
            return creator.get() as T
        } catch (e: Exception) {
            throw RuntimeException(e)
        }
    }
}

and ViewModels provided by this factory were not bound to lifecycle of any activity and fragment. When I changed the creation of ViewModel as:

sharedViewModel = ViewModelProviders.of(this).get(SharedViewModel::class.java)

after OnDestroy() of activity, onCleared() get called.

Thanks, guys!

  • 1
Reply Report