android saving state of many layouts - android

I have a simple chat app where a RelativeLayout with multiple views is created for each message. After the activity is stopped or destroyed all of my added layouts disappear from the parent so all messages are gone.
Sure I could put the ID (along with other values) of each single view into a SharedPreferences object or a database to restore all messages after the activity is re-created.. but is there a simpler way to save the dynamically created layouts..? The parent is defined by XML.

When an Activity (or a Fragment) becomes invisible - its View hierarchy gets destroyed, and you can't overcome that. In fact, you don't need too. The solution is to store the messages inside a database and recreate the View hierarchy on Activity startup based on the database contents. No need to reinvent the wheel here. Hope this helps.

Put your Collection of messages in the Bundle savedInstanceState at OnSaveInstanceState() and restore them in your onCreate() from that.

Related

Fragment view state not saved on back press when using Android Jetpack Navigation

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!

How are inflated layouts recycled in onCreate(), etc?

I have an interface that has two dynamic parts, one of which is more complicated than the other. I had to spend some time with Bundles and onSaveInstanceState(), etc., in order to preserve the state of the first part when the orientation is changed.
Then I turned to do the same with the second, simpler part, and right away noticed that I did not have to do certain things. The layout for this part is inflated in onCreate(), and it contains TextViews and EditTexts whose content can change. This content is retained, but dynamic changes to the layout are not.
When onCreate() is called by restarting the app from the home screen, the changes are not retained.
I have to implement continuity properly via the Bundle anyway, since what is not retained is the state of an object created in onCreate() corresponding to the view. That, and the fact that the behavior is not consistent (restart from homescreen vs. orientation change) make it hard to see this as a "feature", since it implies inflating a "fresh" layout from XML may not always provide a genuinely fresh layout that corresponds exactly to R.layout.whatever.
I'm also guessing this can happen in the context of an Activity's visible lifetime, not just in onCreate(). So what are the rules here?
This content is retained, but dynamic changes to the layout are not
Retaining user-mutable content of common widgets, like the text entered into an EditText, is automatic, from the built-in implementation of onSaveInstanceState(). However, "views... removed from and added to it" (from a previous edition of your question) is definitely not retained by onSaveInstanceState(), and if you re-inflate the layout, such changes definitely will be lost.
When onCreate() is called by restarting the app from the home screen, the changes are not retained.
Well, that will depend upon whether or not the process is still around and whether or not this activity was on the back stack.
So what are the rules here?
If the user is returning to a specific instance of your activity (configuration change, or starting a fresh process from the recent-tasks list), your saved instance state is applied to the new activity instance that is created.
If the user is starting a fresh process without returning to a specific instance of your activity (e.g., home screen launcher), there is no saved instance state to apply.

How to restore dynamic views to the android app?

I am creating dynamic views, Adding them to the layout those views are adding fine.But once i close the app and open it Dynamic views are not visible,I want to display those views after opening the app second time. Will you give me any idea, Thanks in advance.
You'll have to manually add the view's state to the saved instance state bundle, and recreate it from there.
This is accomplished by overriding onSaveInstanceState() on your Activity and/or View. The state will be later available in the creation Bundle (onCreate(bundle)). You can use that data to re-instantiate your views.
The correct OOP way of things would be to create a class for your dynamically created view that implements a custom onSaveInstanceState() method, and then packing it and unpacking it into the Activity's bundle.
This blog post contains details and examples on how to tackle the issue. Some more related info in this other SO question

passing objects to another activity

Situation
In my alarm clock app I start a NewAlarmActivity by clicking a button.
After the user has made all the selections, alarm gets set and `finish() is called.
The matter
I create a new LinearLayout object with images and text within it. That layout must be added to the screen of previous activity (to another LinearLayout placed inside a ScrollView) so the user is able to see the alarm set. Somehow I have to pass that LinearLayout object to the first activity and tell it to receive and add the object to the screen.
How can I do that?
You just need to read some documentation about startActivityForResult().
BTW, IMHO, you should not transport your LinearLayout object between activities, that's ugly.
How to manage `startActivityForResult` on Android?
Starting Activity And Getting Result
This has been asked countless times...
No You don't have to do this. Try the approach of storing your data into a database and then when going into that Activity, build your layout according to the data you have. This is a much better way than passing a layout from one Activity to antoher.

Android TabActivity and dynamic Tabs screen orientation issue

I am adding Views (not Activities) to a TabActivity on demand (meaning that the activity can have zero or more tabs after onCreate is done). Over the time more tabs get added, now I need to save them in a sane way so I can restore them later on. I tried to use saveHierarchyState etc on the individual views, but they are restored without data from the editTexts etc.
So given that I have a HashMap in the activity which maps from tabkeys to views, how would you save this data and restore it?
Okay, I got it :)
First I thought I needed to set the IDs of the Views as described here -- using this approach Android is able to restore the view states. But since my dynamic tabs all use views from the same layout their children all have the same IDs, so android will overwrite the data (The state is saved in a sparse array according to the view ID, so the IDs should be unique) and all views look the same. I fixed that by manually saving the state of my views and reapplying it via:
SparseArray<Parcelable> container = new SparseArray<Parcelable>();
saveHierarchyState(container);
b.putSparseParcelableArray("state", container);
restoreHierarchyState(b.getSparseParcelableArray("state"));
While this approach works I still have to find out if I can let Android do all the work by not setting IDs for the Views in the layout xml file (if that's allowed/possible).

Categories

Resources