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.
Related
I am building my first Android app. I need to add a specific set of headers to each web api call and want them to persist even when the app closes. I implemented them in shared preferences but now I need to drag around a context for every call, which seems like a bad way to do things. I would like to set the values on initialization of the app. Have them usable by the WebAPIHelper object without much trouble, and when the values change, save them. I am using Room so I could save them there.
Is it standard practice to use LiveData or extend the application object to have access to the values for use within an object such as my WebAPIHelper, or is there another, better way? Is it best to persist these values in a database or SharedPreferences?
UPDATE
I have seen some examples of extending the application object like here and here. I would want to get the values from sharedpreferences onCreate and save them to sharedpreferences by calling a setXXX, but I haven't gotten that to work.
Also I was concerned about this statement I found in an article:
"Storing data in the Application object is error-prone and can crash your app. Prefer storing your global data on disk if it is really needed later or explicitly pass to your activity in the intent’s extras."
The implication of this would mean that I would need to pass the header values to the WebAPIHelper object all the time. I am passing the context object everywhere now so I guess it's 6 of one vs 1/2 dozen of the other.
The other way to do this might be to extend the AndroidViewModel class in a BaseViewModel, add the properties there from SharedPreferences so they are available through all ViewModels in the app. Has anybody done it this way?
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 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).
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/
Ddms tells that, when I recall my class called in the past, it performs an onCreate() instead of onResume() that I expected...
I noticed that values that I stored in variables of my class in this case are lost and are null.
I presume that Android decide to do so to free memory resources (isn't it?).
I know that I could use Sharedpreferences to store data in a persistent way and then retrieve... But this is a really dirty way, in my opinion.
So, my question: how to have variables' values preserved also after an onDestroy() (I think?) that Android decided automatically?
Android will terminate your process at any time when you have no visible activities. For example, the user might go into Settings and terminate your app.
Static data members (my interpretation of your "variables of my class" description) are only meant to be caches, at best. They are no substitute for a persistent data model, whether you use a database, an XML file, a JSON file, or whatever.
So, if you want "variables' values preserved", save them someplace persistent.
You might find this page on data storage helpful. If your data is primitive, SharedPreferences are the recommended route. (Why do you think they are dirty?) If you need to store an object, you can use internal storage, as documented on that page.
http://developer.android.com/reference/android/app/Activity.html#onSaveInstanceState(android.os.Bundle)
If you don't like SharedPreferences, then you might want to look into Content Providers Even though Content Providers share data across applications, they also provide functionality for you to store persistent data in SQLlite and files that are available only to your app. In this case data stored in this fashion will be available even after closing and restarting your app.
You can save dynamic state by passing name:value pairs or serializable objects using the Android Architecture and the methods onSaveInstanceState and onRetainNonConfigurationState. You can persist state as explained in the other answers by writing to prefs and doing database writes.
I've been using custom Application class to store data over application life line.
How to declare global variables in Android?