I am working with CustomView which extends some Android view like FrameLayout. In my layout I use a ViewPager with a custom PagerAdapter.
The problem is that my View did not restore it's state when the fragment is re-attached to the ViewPager/Activity. For example, I have three fragments, if I swipe to the last one and come back to the first, the ScrollView is not where I let it : it's back to default, on top.
I know that with a PagerAdapter, not all fragment are active on the same time, basically juste the +1/-1.
I can't find why my View.onSaveInstanceState() is not called, so as onRestoreInstanceState.
The easy answer : it's because I was not setting id to my view (custom or not). Android didn't manage the onSaveInstanceState/onRestoreInstanceState if no id is set to the view.
So as my customView was extending base View, with not extra property, setting an ID to the view solved the issue and so onSaveInstanceState/onRestoreInstanceState are called as it should.
So to summary, use one of this approach :
from XML
<ScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content"
...
android:id="#+id/scrollView">
</ScrollView>
OR from Java
yourCustomView.setId(R.id.myCustomView);
is last case, you add static id to res/values/ids.xml <item name="myCustomView" type="id"/>
Saving State by Default
We now have everything in place for our view to save and restore its state. However, this will not happen by default. If you want instances of your view to save state automatically, you can add this line to the init method:
setSaveEnabled(true);
Whether or not to do this is up to you. Even if your view does not save state by default, users of the view can always enable saving state by calling setSaveEnabled(true), or by specifying android:saveEnabled=“true” in the layout xml.
Related
The design of the application that I'm working on is fairly simple so I've decided to use Activity.setContentView() to switch between the few different layouts it has. This all happens within a single Activity, of course.
To explain it better - let's say that I have a main layout with a simple navigation and a settings button.
The problem is that whenever I show the settings view upon click and later try to set the main view back, it is unusable. It just loads the main layout, but no listeners are set, as if I show a picture.
I've figured out that I should use the setContentView(View view) constructor instead of the one that passes the layout id from the resources. Though, I have no idea how to save the current view..
How to save the current view with all its listeners and stuff to then pass it to the constructor and save my data?
In my app I'm using the Jetpack navigation component and I have an issue with fragment state not being saved when navigating back to a fragment.
When I navigate from MainFragment to SettingsFragment it's via the overflow menu:
NavigationUI.onNavDestinationSelected(item, Navigation.findNavController(view));
When navigating back to MainFragment, the visibility on some views and text in some TextViews is not saved, and my state machine variable has lost its state as well.
I've read solutions where the root view is saved in a global variable in the fragment, and while this solves the visibility issue on views, the TextViews are still empty and the state machine variable is reset.
Is there a proper way to make sure fragment state is saved in this case?
If you're using view model then it can save state for you. However, that only works for simple views. For complex views including some custom views that you created, make sure that you have assigned a unique id to those as Android uses those ids to recover their state. You can use generateViewId() method on View to do so. Worst case, you might need to implement onSavedInstanceState and onRestoreInstanceState on your views.
Also, make sure you have not set to setRetainInstance to false in the xml or code.
While doing that please make sure you use parcelize annotation for your parcelable data models as this can save you a lot of time.
I hope your problem is solved by assigning unique IDs and you don't have to deal with saving state. Good luck!
Is it possible to change the appearance of a fragment (set a different View) during its operation or is it possible only in the onCreateView () method?
You can possibly do it this way:
Return some placeholder view (e.g. FrameLayout) in your onCreateView() and keep reference to it.
Then, you can add/remove other views from your placeholder view, when you need to do so.
However, I think it is not how Fragments are supposed to be used. (changing its views rapidly during runtime)
I'll answer my own question.
Not to create chaos in the management of widgets. It is better to use child fragments or show/hide necessary widgets. The answer found here.
I just need help cleaning up some information that doesn't make sense to me, with use cases if possible.
WHAT I UNDERSTAND:
With fragments in android, I understand that if you plan on replacing them you need to have a container view, preferably a FrameLayout, and add the initial fragment to the container during the activities onCreate method. But there is one thing that continues to not make sense to me.
WHAT I DON'T UNDERSTAND AND NEED HELP WITH:
What rules are there regarding where/how the container view is set up, if there are any. Android Developers site makes it look like the container view needs to be it's own XML layout file, but it doesn't say that and I have seen examples on here with FrameLayouts nested inside of your typical layout files, but they are all specific uses and I need to understand the rules of setting a container up.
There are no rules. You just need any ViewGroup -- position and size it however you want. When you add the Fragment into it, it will behave just as if you'd created the Fragment's View manually, and called yourViewGroup.addView(fragmentView).
FrameLayout is typically used just because it makes a good container with no real behavior (you just give it a size and position and let the fragment fill that container).
There's absolutely no need to make the container view its own layout file. In fact, if you want the Fragment to take over the content view of the entire Activity, you could even just add the Fragment to the Activity using the ID android.R.id.content.
I am doing a very basic layout inflation of a XML layout into a linear layout container. The inflation is working however when I rotate the view that was inflated disappears (as expected) what I want to know is there a way to save the inflation or view group such as through on save instance state so that I do not need to inflate again since I read layout inflation is expensive!
You shouldn't worry about View inflations being expensive at orientation change! This is how Android works, on orientation change your Activity gets recreated. Period.
But if you really need to (you probably don't), it is possible to force an Activity to not get recreated, in short use android:configChanges="orientation" in your manifest activity declaration. More about this here.