Fixed
Status Update
Comments
il...@google.com <il...@google.com>
cl...@google.com <cl...@google.com>
fa...@hotmail.com <fa...@hotmail.com> #3
I look closer and now I'm not sure what is the best behavior.
Currently keys()
does what javadoc says "all keys contained in this SavedStateHandle". Technically, before first onSaveInstanceState keys corresponding to SavedStateProviders aren't in the SavedStateHandle. However I can see, that SavedStateProvide is kinda promise that value will be in the SavedStateHandle in future.
I think we can do smth like:
fun keys() = mRegular.keySet() + mSavedStateProviders.keySet()
Ian, what do you think?
Description
Version used: 2.1.0-alpha01
Devices/Android versions reproduced on: API 28 emulator, Chrome OS
MediatorLiveData.addSource doesn't manually check for null source argument (annotation is there, which is good)
It's possible to accidentally add a null (or not yet initialized) source.
The issue is buried until the MediatorLiveData is observed, making it hard to find the original issue.
Best solution would be a quick check of the variables and fast fail before processing. e.g. assertNotNull(source)
- Sample project attached
relevant code:
private val mediatorLiveData = MediatorLiveData<Int>().apply {
// Here is the mistake, (allowed at compile time).
addSource(dataSource) { value = (it ?: 0) + 1 }
}
private val dataSource = MutableLiveData<Int>()
// This triggers the exception
mediatorLiveData.observe(this, Observer { // process })
Error output without check: (unhelpful unless you know the internals of MediatorLiveData)
2019-01-18 10:58:39.891 6385-6385/? E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.google.example.mediatorlatecheck, PID: 6385
java.lang.NullPointerException: Attempt to invoke virtual method 'void androidx.lifecycle.LiveData.observeForever(androidx.lifecycle.Observer)' on a null object reference
at androidx.lifecycle.MediatorLiveData$Source.plug(MediatorLiveData.java:141)
at androidx.lifecycle.MediatorLiveData.onActive(MediatorLiveData.java:118)
at androidx.lifecycle.LiveData$ObserverWrapper.activeStateChanged(LiveData.java:436)
at androidx.lifecycle.LiveData$LifecycleBoundObserver.onStateChanged(LiveData.java:394)
at androidx.lifecycle.LifecycleRegistry$ObserverWithState.dispatchEvent(LifecycleRegistry.java:355)
at androidx.lifecycle.LifecycleRegistry.forwardPass(LifecycleRegistry.java:293)
at androidx.lifecycle.LifecycleRegistry.sync(LifecycleRegistry.java:333)
at androidx.lifecycle.LifecycleRegistry.moveToState(LifecycleRegistry.java:138)
at androidx.lifecycle.LifecycleRegistry.handleLifecycleEvent(LifecycleRegistry.java:124)
at androidx.lifecycle.ReportFragment.dispatch(ReportFragment.java:123)
at androidx.lifecycle.ReportFragment.onStart(ReportFragment.java:83)
at android.app.Fragment.performStart(Fragment.java:2548)
at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:1334)
at android.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManager.java:1576)
at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:1637)
at android.app.FragmentManagerImpl.dispatchMoveToState(FragmentManager.java:3046)
at android.app.FragmentManagerImpl.dispatchStart(FragmentManager.java:3003)
at android.app.FragmentController.dispatchStart(FragmentController.java:193)
at android.app.Activity.performStart(Activity.java:7165)
at android.app.ActivityThread.handleStartActivity(ActivityThread.java:2937)
at android.app.servertransaction.TransactionExecutor.performLifecycleSequence(TransactionExecutor.java:180)
at android.app.servertransaction.TransactionExecutor.cycleToPath(TransactionExecutor.java:165)
at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:142)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:70)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1808)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6669)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)