Apr 22 | 7:20 PM |
Mark M. | has entered the room |
Apr 22 | 7:25 PM |
Mark M. | turned on guest access |
Apr 22 | 8:05 PM |
Eric | has entered the room |
Eric |
Mark nice to see you
|
Mark M. |
hello, Eric!
|
Mark M. |
how can I help you this evening?
|
Mark M. |
(assuming that it is evening where you are!)
|
Eric |
What is the advantage of using viewLifecycleOwner instead of this when observing a livedata? ViewLifeCycleOwner is only available once a view is inflated so if I go back to my fragment I will always observe the livedata again
|
Apr 22 | 8:10 PM |
Mark M. |
you should choose a lifecycle that matches what you are trying to do with the observed data
|
Mark M. |
so, for example, suppose that you want to use the observed data to update the UI of the fragment
|
Mark M. |
for that, you should use viewLifecycleOwner, as otherwise you might be handed data when you have no UI to update
|
Mark M. |
viewLifecycleOwner is tied to the lifecycle of the views -- onCreateViwe() and onDestroyView()
|
Mark M. |
if, on the other hand, you do not want to update the UI of a fragment based on the LiveData, then using `this` for the lifecycle may be reasonable, if unusual
|
Eric |
you make a good point. I was about to complain about observing the data twice using viewLifeCycleOwner inside of onCreateView but then I realized that the naviation component uses "replace" to navigate between fragments. Replace will remove and add a fragment, destroying its view. So it seems to be working as intended, once I go back to my fragment my view needs to be created again, and I want to fill it with the contents of my livedata
|
Apr 22 | 8:15 PM |
Mark M. |
that sounds about right, though I haven't poked at the guts of Navigation to know exactly what sort of FragmentTransaction it uses
|
Eric |
are you familiar with the SingleLiveEvent class? I read an article saying it is an observer that fires once instead of twice. So in our scenario on back press our observer would not be notified a second time
|
Mark M. |
there isn't a class like that in the Android SDK, though it is easy enough to create
|
Mark M. |
basically, the single live event pattern has you use a LiveData<Event<T>> instead of a LiveData<T>
|
Eric |
I'm trying to understand when to use a livedata vs a specific SingleLiveEvent (practically)
|
Mark M. |
mostly, it is for configuration changes
|
Mark M. |
suppose we have a fragment with a viewmodel
|
Mark M. |
the viewmodel loads some data from somewhere for the fragment to display
|
Apr 22 | 8:20 PM |
Mark M. |
for that, we use LiveData<T>, so that if we undergo a configuration change, the new fragment instance gets the old viewmodel and is immediately handed whatever is already in the LiveData<T> when it starts to observe it
|
Mark M. |
so, the fragment can immediately display the cached data
|
Mark M. |
however, let's suppose that the data-load process could fail, such as having some sort of network error in a Web service call
|
Mark M. |
and the product designers said "in case of an error, show a dialog"
|
Mark M. |
one approach says that the viewmodel emits the error information in a LiveData<T>, and the fragment observes that to show the dialog
|
Mark M. |
and, suppose that you elect to use a DialogFragment for that dialog
|
Mark M. |
now, after a configuration change, you wind up with two overlapping dialogs
|
Mark M. |
Android recreates the DialogFragment automatically, so you get its dialog
|
Mark M. |
and, your primary fragment gets recreated, observes the LiveData<T> again, gets the error information, and shows another DialogFragment
|
Mark M. |
the technical term for this is: "bad" :-)
|
Mark M. |
what we *really* want is a guaranteed one-shot delivery mechanism, so we know that our error information is consumed exactly once, not more than once (and not accidentally dropped on the floor while a configuration change is in progress)
|
Mark M. |
the Jetpack doesn't really have one of these :-(
|
Mark M. |
so, Google developer relations folks came up with the single live event pattern: LiveData<Event<T>>
|
Mark M. |
your fragment, after the configuration change, still gets the data handed to it again automatically... but the job of Event is to track that the data was already used once, so you do not try using it again
|
Apr 22 | 8:25 PM |
Mark M. |
in Kotlin with coroutines, we would use a Channel instead
|
Mark M. |
or, with RxJava, we would use a PublishSubject
|
Mark M. |
both of those need extra attention from a lifecycle management standpoint, but otherwise they do not cache results the way that LiveData does
|
Mark M. |
you can see an implementation and discussion of the single live event pattern in *Elements of Android Jetpack*
|
Mark M. | |
Eric |
on a rotation change why does android create 2 dialogs? Doesnt the first dialog get destroyed instead
|
Mark M. |
a DialogFragment automatically recreates its dialog
|
Mark M. |
and Android recreates the DialogFragment after the configuration change
|
Mark M. |
now, one solution is to simply not use the DialogFragment, and to manage the dialog more directly yourself
|
Mark M. |
for the dialog case, that can work
|
Apr 22 | 8:30 PM |
Eric |
does a DialogFragment work differently from a DialogFragment, because a fragment gets destroyed on rotation unless you retain it
|
Eric |
Fragment
|
Mark M. |
active fragments (those attached to an activity) get destroyed and recreated on a configuration change
|
Eric |
a DialogFragment work differently from a Fragment
|
Mark M. |
both DialogFragment and Fragment get destroyed and recreated on a configuration change
|
Eric |
correct, so I thought it would get destroyed and recreated instead of resulting in 2 dialogs
|
Mark M. |
except that your original Fragment created another DialogFragment in response to getting the LiveData emission again
|
Eric |
I'll try to create an app to test your scenario. I appreciate it :)
|
Eric | has left the room |
Mark M. | turned off guest access |