I have a global empty state fragment that is shown whenever a network request fails to reach API. The fragment shows a simple error message and a "Retry" button.
I can navigate to the fragment from any other fragments of my app so the "parent" fragment is never the same.
I want to find a way to pass a callback to the empty state fragment so that whenever the user clicks on the "retry" button, I can retry the network call that triggered the empty state and check if the call worked in order to navigate back to the previous fragment.
I think that the recommended way should be using viewModel but since the empty state fragment could be call from any other fragment, the view model containing the network call would also, never be the same.
I wanted to know what would be the best approach here.
Thank you.
Related
Since Fragments were introduced I keep my eyes open for a good solution to update a Fragment to which I'm going back to.
This is my scenario:
I have a One-Activity App. When the App starts it shows a FirstFragment. With a button click the user can open a SecondFragment. Both Fragments are full screen and will be opened via androids NavController.
Note: Both fragments get their data from a rx-based repository. The repository and its underlying classes handle all CRUD operations.
What I want to do:
Updating the FirstFragment as soon as the user clicks back on the SecondFragment OR in other words: I want to update the FirstFragment as soon as it comes on top from the background.
The Problem
The FirstFragment gets no callback or livecycle event if it comes into view again.
In the past I solved this problem with a ListenerInterface that was triggered in the activities onBackPressed or with a broadcast event. But is there no better solution? I question if there is a possibility via LiveData or via NavController or anything else. Or does anybody know how google solves this problem?
What I NOT want to do
As my data layer is based on rx I could of course have a BehaviourSubject that I subscribe on in the FirstFragment. Then when I switch to SecondFragment I could keep the subscription undisposed so the FirstFragment will be updated as soon as i call onNext on the BehaviourSubject. I've seen apps doing this and it seems wrong to me. In my opinion a subscription should be disposed as soon as another ViewModel steps into place.
Thanks in advance
Android, notify backstack fragments on some change
Code for question on Github
I have a app which is using fragments + viewmodels. In one fragment I need to present a list of options to the user when they hit a button. I'm doing this using an AlertDialog builder and it works to solve that problem. But if I open the application, hit the button to show the alertdialog, dismiss the dialog, and then rotate the phone to trigger a teardown/buildup the alertdialog get's reshown.
I'm using Android's databinding to bind ui stuff to the ViewModel(not sure if it matters). So the basic flow is:
App starts
Fragment subscribes to 1 observable in the ViewModel
User clicks button
Due to databinding the click is handled in the ViewModel by the method buttonClicked()
Inside vm.buttonClicked() function I get data and update the observable the fragment is observing
Fragment see's new data in observable
Fragment creates AlertDialog in code and shows dialog to user
User either makes a selection or dismisses the dialog
User rotates phone, causes lifecycle change
When the ui get's rebuilt, it shows the AlertDialog again
I have created a simple demo on github.
If you clone that repo then start the app but DONT hit the button, orientation changes go as expected. If you click the button and dismiss the dialog then rotate the phone, you'll see that the AlertDialog get's reshown.
ViewModel's lifecycle is different than of the fragment. When the orientation changes the Fragment gets recreated but the ViewModel stays.
Now what's happening is, when you update the value of the MutableLiveData it broadcasts an update to the Observer; when the Fragment is recreated on rotation change, it subscribes to the LiveData all over again and since there is an update on the value, the MutableLiveData broadcasts the update to the newly subscribed observer.
So you should, for example, save your fragment state in onSaveInstanceState, use the savedInstanceState to get the last update to the MutableLiveData value and check if a change had happened in the observer before showing the dialog.
Or you can move the dialog logic to the on click handler. Showing a dialog in an Observer is not a good approach in my opinion.
If you are working with LiveData and events, this can help you to tackle some scenarios. In summary, you should work with SingleLiveEvents
I have a main activity. From this activity user can navigate to profile and in profile user can edit settings.
What I want is: when the user makes changes, I want to refresh the fragment in main activity according to these changes. As I can only update the fragment that main activity is showing when that activity came to top again. So how can I tell main activity that data has change and update the UI accordingly.
So I was wondering what's is the best way to handle that kind of scenario.
Consider creating a custom BroadcastReceiver inside the Fragment class, and on any change of settings send Intent with your custom Action.
If profile is an activity, start it using startActivityforResult, and get new data in onActivityResult if fragment instance isn't null , call some method say update in that fragment. If fragment instance is null, create new one using new data.
If profile is another fragment in the main activity, then store the changes in SharedPreferenceManager. In On Resume of your MainActivity's FirstFragment fetch data from SharedPreferenceManager. If it isn't same redraw that fragment else leave it.
I have FragmentX in a ViewPager. FragmentX has EditText's in it and a Button. The user presses the Button and FragmentY replaces FragmentX. The user then presses back and FragmentX has lost all of its input from the user.
How do you either:
a) Save the data in FragmentX before FragmentY appears then FragmentY is replaced by FragmentX retrieve the data and fill in the EditText's in FragmentX
(please don't reply with OnSaveInstanceState, as this does not work unless the Fragment is destroyed, which in this case it is not)
b) somehow keep the data in FragmentX so it is there when we go back to FragmentX from FragmentY..
Any suggestions?
Using addToBackStack() might help in your case.
If you return to a fragment from the back stack it does not re-create the fragment but re-uses the same instance and starts with onCreateView() in the fragment lifecycle, see Fragment lifecycle.
So if you want to store state you should use instance variables and not rely on onSaveInstanceState().
Check this out: Maintaining fragment states
I am now saving the data in FragmentX to SharedPreferences and overriding onBackPressed in the Activity, and have created a function in the Activity called popFromBackstack where the popBackStack() occurs.
In the functions in my Activity where i replace my Fragments i am now saving the data in FragmentX into SharedPrefs before the replace. I am also checking after the replace if the new Fragment is FragmentX and, if it is, i am filling the data into FragmentX from SharedPrefs.
I am also saving the data from FragmentX in onBackPressed in my Activity (if the current fragment is FragmentX), incase the user presses the back button.
I have also created a public static activity called popBackStack() in my Activity which i call from Fragments to pop the backstack. I am also saving the data from FragmentX here (if the current fragment being popped is FragmentX). Once the Fragment being popped is popped i am checking if the new Fragment is FragmentX, and filling in the data if it is...
Long winded approach but i couldn't figure out any other reliable way. This is working perfectly.
I suggest following guidelines that Google provides and implement an interface declared in your Fragment and save the Bundle or whatever object you want in the activity. Then, in your newInstace() static factory method pass that Bundle and recreate data as usual. Since you are using a ViewPager and it will always render the second fragment before the button is pushed (I assume your second fragment is in another tab) you still need to manage it via an interface. When the back button is pressed, the data will still be there, unless it is destroyed, and you still need to implement onSaveInstaceState() for that matter. You can also use setRetainInstance(boolean retain). See here for more details
in my fragment activity i need to display some 3 fragment at a time, one fragment contains set of buttons, another contains list etc...
If a click occurs on button, then i need to change the list fragment and show the details.
To communicate "show detail fragment to parent" its better to keep an interface and register for it and when anyone clicks on button simply notify click happened or should i create the fragment activity method showdetailsfragment via object of parent activity?
is it better to create interface and notify when event occurs from fragment? or use parent object to communicate or any other best alternative method?
To quote the official guide:
"In some cases, you might need a fragment to share events with the activity. A good way to do that is to define a callback interface inside the fragment and require that the host activity implement it. When the activity receives a callback through the interface, it can share the information with other fragments in the layout as necessary."