I've been using singletons to store data that is loaded when my application started. This data is used throughout the lifetime of my app, but doesn't need to be persisted for future launches. I've started hitting the issue though that my singletons are garbage collected and their data is wiped. Does the singleton pattern just not make any sense on Android? Using local storage or a local database seems like overkill, but I'm not sure what else to do to guarantee my data is safe for the lifetime of my app.
Thanks!
I've started hitting the issue though that my singletons are garbage collected and their data is wiped.
No, they are not. By definition, a singleton (static data member) cannot be garbage collected.
Most likely, what you are seeing is that your process is being terminated.
Does the singleton pattern just not make any sense on Android?
As a caching mechanism, it is fine.
I'm not sure what else to do to guarantee my data is safe for the lifetime of my app
A static data member is "safe for the lifetime" of your process. If you want data to survive process termination, you will need to store that data in a database, SharedPreferences, or some other sort of file.
Are you holding onto a reference to the singletons in the Application (http://developer.android.com/reference/android/app/Application.html) level of the app? That should keep them persistent for the most part (unless they're byte[] or something else huge).
The safest bet, however, is to assume that data will be garbage collected and structure your code with that assumption. If it's something from the web, define an asynchronous callback to load the data and then populate your views. If it's something local that is not user-generated, use the async to grab it from disk. If it's user generated, you might need to set up a database (which you can empty when you restart the app) to keep track of data.
But, if you haven't, tried keeping references to your singletons in the Application first. Brief intro here: http://www.devahead.com/blog/2011/06/extending-the-android-application-class-and-dealing-with-singleton/
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.
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).
I want to keep some objects in memory for operations in all the activities of my app and I also want to store those objects when the app closes. Which is the most efficient way of doing this ? Some possibilities that I can think of are:
1) Keeping local copies of objects in all the activities, serialize them and pass them through intent.
2) Keep local copies of objects in all the activities, serialize them and do file read and write on activity resume and pause respectively.
3) Make them static variables but I don't know when to do the file read/write operations in that case? This approach may leak memory.
4) Use Application object and define my objects as variables in that object. Since it has a definite life cycle like activity, I can do read/write accordingly.
I recommend your approach number 2. The reason is that there is no such thing as "the app closes". Android tries to keep it in memory until the memory is needed for other purposes. The process of your app is then simply killed, you don't get any callbacks called.
Singletons or the Application object can be used to cache the objects if you are careful to load and store them as necessary. However, this also means, that the memory used for them is only reclaimed if the app process terminates.
It depends on your data. All approaches are good in some cases.
I think you have 2 options:
keep data in sqlite. It is easier then files and faster. When activity starts request required data from db and show it. (use files if you really want)
create a singletone class to store data. Data will be loaded in memory and you can access it very fast. When data changes save it to sqlite or file. google "share data between activities"
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?