Of late I have been into an issue which has been really difficult to sort out.
I have an Activity A which has a view pager with fragments. I am loading data from server and feeding into the views. The data received from server is stored in a singleton class which can be accessed across the application. Now user moves to another activiy B which uses the server data through singleton class.
Now when user presses home and launches variety of application, my app gets killed in background. When I relaunch the application, OS try to load activity B again with its saved state(I am not doing anything in onSaveInstance), but the data in singleton class is already lost and app crashes. The thing is I cannot get the server data again in this activity. Should I save the entire data in onSaveInstance of this activity? Is it not encouraged to use singleton class to store all your data?
What is the ideal way to handle situation like this?Any help is appreciated.
How sensitive is the data? In Android is is not recommended to use a skeleton to move your data around(Passing it through intent? Static(please say no)). Ether way was commented you should probably store the data to main memory. Android provides a few options besides actually writing it to a file. Depending on how much data and its structure there are a few options.
ContentProvider & ContentResolver, Basic Overview. I would not recommend this unless you plan on making the data accessible to other applications.
SQLite. Good if you have preexisting sql knowledge or large amounts of data where a relation db is needed.
SharedPreferences. As its name implies is generally used for storing user presence data, but it can also be used to store any data. I would not recommended it where there is a lot or complex data is needed to be stored.
File. Good old java file classes, no explanation needed.
With our data I would recommend creating a DataStore managing class which handles the io to any of the above methods, so when referencing the data you simply pull from that class.
To avoid such situations, you should relate to these:
App crashes when restoring from background after a long time
http://www.developerphil.com/dont-store-data-in-the-application-object/
Related
Will the Object be around for as long as the app is in the background? Does anyone know when a Kotlin Object get removed from memory and reset in Android? Should I just use a ViewModel instead?
When the app is in the background, you can't know what the system will do with it so you can't store in memory data you want to persist.
You have different solutions:
If it's data from a server, you can make the call again if the app has been destroyed between the moment the user put it in the background and the app is brought back.
You can store the data locally.
In the second case you have 3 solutions:
Persist the data into a SQL database, using a solution like Room for instance. This is usually the way to do it.
Persist the data into the Shared Preferences. Used for light data, like settings or small preferences
Store them into a file (usually not a good approach)
A ViewModel is not a way to persist data. It will only persist data in memory. It is good to keep the data when the UI has been destroyed (app changes orientation, or Fragment put in the backstack for instance)
But if the app is killed (for any reason), so will be the ViewModel and everything it contains.
However following a MVP or MVVM (using ViewModel) pattern is a good way to build you app as it decouples the UI from the logic and helps with tests.
Currently I'am developing app which having a bad API. I have a situation where I have to use data received from network call in a activity, which is 2 steps away from the activity where I made the network call. In other word all the data necessary fill 3 activities comes on this one network call.
So I pass necessary data between activities using Intent Extra. It is not easy to maintain and It takes noticeable time to switch between activities.
I know one possible solution is to store data in database. and access those data from different activities. It feels like a bad practice because no use of those data after user pass 3rd screen.
Is there any better technique to handle this?
You can put all your network logic in the separate class, cache data in some variable and use it in your activities (you can use singleton class or injecting by dagger).
Also you can read about Clean Architecture and get some good practices from it.
If you don't want use anything from above, you can remove data from database after using and not store it forever. Or you can use SharedPreferences if your data is not complex.
I am currently facing a problem with persisting object state in an android app.
I have some kind of multi level master-detail flow.
For example, I have a list of Clients. Each Client has multiple Orders and each Order has multiple articles.
Until now I did the following:
When you click a Client in the MasterActivity I write the Client into the Bundle and open the DetailActivity.
In the DetailActivity I read the Client from the Bundle and display it.
This worked more or less fine most times, however it now happens, that an object is too big to be serialized (for example a Client with a lot of Orders).
Therefore I wanted to serialize only the ID of the Client and load it from the database inside the DetailActivity. Usually this approach works fine but I have one situation where it does not work:
The Articles are only saved, when you save the Order (their Master). So if you create a new Article for an Order and you don't save the Order, the Article isn't saved too.
That means, that I always need to have the full object, reloading it
from the database inside the DetailActivity means, that I loose all the unsaved changes. However, persisting it, using the Bundles could exceed the limit (500kB to 1MB).
So my question is, what is the preferred way to persist such data?
A nicer way is to create your own singleton class which points to data you want to transfer between activities.
I suggest DataManager singleton activity which has Article articleToPass
Make the setter set the articleToPass to point to what ever you want.
and the getter or reader, will read fetch the article and nullify the articleToPass.
manage your app data using this DataManager singleton (This dataManager singleton can be initialized either in the extending Application class or MainActivity).
Incase you must persist the object when app is destroyed and loading back:
Create from Article object a DB entry which contains all data you need (I see no reason why saving data you don't need here)
Dump all data to some file (Using Shared Prefs, key and values)
When entering the Details screen you want make a query to a sever of yours requesting all data you need by ID or such.
Convert all object you need to JSON (simply using GSON), and dump the JSON to a file, and load it when you need.
I think the resolutions above are enough :) hope i helped
You can subclass your own MyApp class from Application, specifying it in your manifest. This class is a singleton and is available all the time the android application is running like this (MyApp)getApplication().
So, in a field of this class you may keep some temporary data you need to keep between activities.
You have to check if this field is not null though because the OS can terminate your app anytime. In this case you will have to reload the data. You can keep some index of what data to be reloaded somewhere in the SharedPreferences.
Now I'm facing some problem in Android when memory is low or the application is killed by system.
Scenario 1:
I set some static members in a class, I found in some situation , it will be deleted by system when the application is still running.
My problem to this is : when does this kind of GC run?
Scenario 2:
If I switch to another large application and then switch back to my application ( named App_A). App_A sometimes will be recycled by system and restart the last activity when it be switched back.
But there are some application-wide data (like login info) I saved in a singleton.
My problem to this is : Dose the application-wide data saved in singleton will be deleted?
If so, is there a appropriate way to restore the data?
My effort is:
To Scenario 1, I will avoid to use static member directly.
To Scenario 2, I will save those data into file , after it be deleted, I pass Context to each public function to let each of them have the ability to restore the data. But I think it will be unfriendly when the function is used in some situation which need run quickly.
I can only answer about Scenario 2.
Android will try to keep recently used apps in memory, but if the user switches to another app and memory starts running low, the OS has the option to kill the recently used app to make more memory available to running applications.
I had the same problem, where I had some user-context data like username in a static singleton. This data would disappear when returning to the app after using a number of other apps.
The way I solved this problem was to use the activity's intent. Since the user data was retrieved at the beginning of the app, I would simply pass this data to subsequent activities in their intents. Because the OS stores the intent and uses it to recreate an activity not in memory, my data was no longer vulnerable to being garbage-collected.
Also consider other means of persisting data: Shared Preferences, file system, SQLite database. But never count on static data from previous execution being available at the start of an activity.
It is generally bad idea to use singleton to save some data.
Best practice is using any persistent storage - SQLite, Realm,JSON, or any file.
Easiest way is saving your login data for ex. in JSON - then in Application class parse it in onCreate method into POJO - then you can get it from any place of your app. And store to file when app is closing or on any change.
Anyway I suggest you to read Android guides about persistence, memory management and performance tips.
I wonder about following, maybe someone can clear that up for me:
I am having an application which loads some json feeds initially on application start.
This data is needed in each fragment, and the standard way for me would be to retrieve it in the MainActivity and to pass it in bundles to my fragments.
Downside: Serialisation, complicated Datasync, lots of bundling and unbundling code.
What about just putting the data in some global, static DataSource class and accessing it from the fragments/activities? Would be super simple - however, it seems to have a drawback:
When fragments are resumed after the app stayed in the background for a while, it seems that all global static data is lost.
How would you handle such a usecase? Is there a way to persist and reload static data without having to map everything and store it into a DB?
I am having an application which loads some json feeds initially on application start.
Nobody has universal, perpetual connectivity. Hence, you need a persistence strategy to deal with the cases where the user wants to use your app but is unable to connect to the server, for whatever reason.
When fragments are resumed after the app stayed in the background for a while, it seems that all global static data is lost.
That is because your process was terminated, and your JSON is not part of your saved instance state. Large model data, like your JSON, usually is not something you want as part of your saved instance state anyway.
How would you handle such a usecase?
Use a file or database on internal storage as a backing store. Static data members are only a cache for such a persistent store, nothing more.
Is there a way to persist and reload static data without having to map everything and store it into a DB?
You already have the JSON. Write it to a file, if nothing else.
As noted earlier in my answer, you need to have a plan in mind for dealing with a lack of connectivity or other reasons why these feeds cannot be retrieved. That should tie into your persistence strategy. The Internet updates your persistent store (and, along the way, updates any in-memory caches).