I need to share a list among all my activities, so I've extended my application class in order to store inside it my list :
public class MyApplication extends Application {
public ArrayList<Object> theList = new ArrayList<Object>();
}
It works fine, except sometimes when I resume the app, the list is cleared. The list is not null but is empty (while I never clear the list in my code of course).
I wonder why the list is cleared.
If it's because of the garbage collector, the list would be null, isn't it ?
Do you know a way to keep data even after resume ?
Your list lives in RAM, and not on the device storage, so if the app is removed from RAM by the system, even momentarily, the data will be lost.
What you need to do is save the data into a db or shared prefs but also have an in memory model of it as you do.
In MyApplication.onCreate method, start an ASyncTask to load the data from the db or shared prefs, so each time your app is restarted (by the system), it will load the data correctly. Use a boolean in your MyApplication class so you can check if the init is finished, and make it readable from your activities that need the data, so they know if loading data from db is in progress (show loading UI in this case).
Each time you add or remove an item from the list, also carry out the same operation on the db/shared prefs, so your saved data is always in sync with your in memory model.
Whether you choose a db or shared prefs depend on the type of data you have, but as it's a list, I'm guessing a db would make more sense.
Related
I have created an app with two activities as the activities with two separate lists.
Let's call them: Activity1 and Activity2.
With the home screen of the app called the MainActivity.
As soon as the app is launched, the MainActivity is created and notifications appear in the notification bar based on the list item's statuses.
I've had a look at the lifecycle of Android but I can't understand and figure out where to load the lists and when to save the lists. Also, what is the best way to save large list data in Android to internal storage? Json? Csv? File type basically? :)
For example, would I load both lists when the MainActivity is first created, onCreate(). And then save the list of(for example) Activity1 when the user navigates away from Activity1, onPause()?
To reiterate, this is what I need help on:
I've had a look at the lifecycle of Android but I can't understand and figure out where to load the lists and when to save the lists. Also, what is the best way to save large list data in Android to internal storage? Json? Csv? File type basically? :)
Thank you for any help! :)
As you may have already known, onCreate will be call when Activity is instantiated, so all initialization, including populating the Activity with list data loaded from a file or shared preference. In terms of when to save the list data, it totally depends on how you want to modify the data, as data only needs to be saved when it's changed from its original state.
Of course, you can also load data every time onResume is called, and save data again when onPause is called, just to make sure data is synchronized if you have multiple applications modifying the same list data.
There are many different ways to save list data. I would recommend to use SharedPrefernce as it will save you some troubles. Please read this for how to save ArrayList to SharedPreference. If you don't like this, you can always save the data to a file with some standard format (JSON, XML, etc.) and parse the data when reading from and writing to the file.
A good entry point to load a data is in "OnResume". It is called every time your activity will be presented to the user.
Saving your data can be placed in "OnPause".
"OnCreate" is only called when the activity will be created, which will happen only once for your MainActivity.
In my app, I inject some singleton manager objects using dagger.
Suppose one of these managers, say myManager, keeps data in a list, say myList.
Also I have a BroadcastReceiver class, say myBroadcastReceiver which calls one of myManager methods, say myMethod, when it receives some particular intents.
If I open my app and wait until myList is initialized, then press home, and after that myBroadcastReceiver receives the intent and calls myMethod, myList is null (though myManager itself is not null).
I can't figure if it's a matter of android's natural behavior or if I've actually made a mistake that it happens.
I think your singleton class is getting unloaded due to low memory you need to save that list in onSaveInstanceState(Bundle outState) and retrieve the same in onCreate method
You could either implement a "save state" solution using onSaveIntanceState functionality provided by android in your activity or service or whatever component you're using
Or you can save your data locally in a file or even better a sqlite database, which could be very simple and straight forward to implement.
And by keeping your list "in memory" synch'd with the local storage, you'll never lose any data.
Simply using lazy loading, each time your list is null, fetch the data back from local storage.
I am developing an Android app and I would like to avoid reloading similar data when it comes from the same Activity using the same extra.
Specifically, when I launch my Activity 'A' with extra, I use this extra to load remote data from server.
From this Activity, I can relaunch 'A' with different extra and so on.
Example :
A:id1 --> A:id2 --> A:id3
But, it can also be an extra that I already loaded :
A:id1 --> A:id2 --> A:id3 --> A:id1
In this case, I wouldn't request the server again or lose the activities stack.
As I understand, "onSaveInstanceState" allows to save one instance of one Activity, but in my case, it's multiple instances of same Activity (with differents extras).
So, is it the solution to manage a list of saved instance states (bundle) for the same Activity ? Or something else ?
Thanks in advance
The onSaveInstanceState method isn't used in the way you describe. Check this out, it's the documentation for the Activity Class, specifically the Activity Lifecycle section. onSaveInstanceState is a method that gets called when the OS has to kill an Activity for some reason. It allows you to populate a Bundle which will help recreate that specific instance of the Activity where the user left off. Usually this happens because the user switched to a different app and the OS is killing the Activity to reclaim memory, but also happens on screen rotation, so it's a nuance of the platform that is important to at least be aware of.
As for your question, what I would do is use a database to store the information that is retrieved from the server. When you start an Activity, you can first check to see if the data that needs to populate that Activity exists in the database. If it does, load and display it from there, else make the server call.
This is nice, because the data will be persistent over multiple uses of the App. Going further, if the data from the server has the potential to be stale, you can easily extend this to display the data from the database initially, and fire off an asynchronous request for the data that will update both the UI and database when it returns. Your user will almost never be in a state where they're waiting for things to load, which is always a good thing!
Here's a good tutorial on the basics of implementing an sqlite database. This will also give you the added benefit of keeping the data stored over separate runs of your application.
As an alternative, if you don't really need the persistence or other features of the database and don't think that the overhead is worth it, you could create a Singleton class which keeps track of the data as its returned, perhaps implementing it using the Application class. It's important to note (and bringing us full circle) that any in-memory method of storing this data should be managed with onSaveInstanceState to ensure you don't lose any data if the Activity is killed at an unexpected time.
+1 for MattDavis' answer, but I'd also suggest you use what's known as the "singleton pattern".
Essentially, this is a way to cache things in memory. You create a class whose purpose is to hold all the database data you don't want to keep reloading. There's a single global instance of this object, which is initially null. You call a static method that returns that instance. If the static method finds that the instance is null, it creates the instance, populates it from the database, caches it, and returns it to the caller. From that point on, all requests for the instance just return the cached copy. If your app gets killed by the system for lack of resources, and started again later, it transparently re-creates the instance as needed.
This is a very common implementation, and works in a multi-threaded environment:
public class Singleton {
private static volatile Singleton instance = null;
private Singleton() {
// This is the place where you initialize the instance
// from the database.
}
public static Singleton getInstance() {
if (instance == null) {
synchronized(Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
I use this pattern in a lot of places; it's very handy.
To really do it right, you should also implement onLowMemory() or onTrimMemory() in your activities to release the singleton instance when resources are tight.
I have a ListView that is displaying data from a large dataset. The data is retrieved from the web and put into a List<Data> (i.e. in memory) by a background task. (Think email inbox with polling updates.)
My problem is how to pass that data to the ListFragment/ListView/ListAdapter to display.
This List isn't permanent (so not in a Content Provider) but lives longer than activity (it's updated in the background when the activity isn't alive yet).
The only options appears to be:
Pass it via an Intent/Bundle. This requires serialization on some level which will be very expensive for my long list, especially as each time the List updated in the background, I have to set a new List which means the entire list gets re-serialized.
Create a Singleton that provides the list from anywhere in the program, and access SingletonListProvider.getInstance().getList() from my ListAdaptor. I don't like singletons and I'm worried about concurrency.
Use a ContentProvider. Seems overkill for a simple List<> that currently lives in memory
Are there any other options?
It seems I have little control over how the Activity (ListFragment in this case) is created so I can't just pass the List as a constructor parameter.
Best way is to use Database, especially if your data-structure large.
By the way, you shouldn't create ContentProvider enough to extend SQLiteOpenHelper.
http://www.vogella.com/articles/AndroidSQLite/article.html#sqliteoverview_sqliteopenhelper
I have a ListView with a custom ArrayAdapter, that shows orders from an ArrayList. These orders are supposed to be synced with my server. There I have an API, which I am requesting for new orders, and if there are any, I get an XML of the order back. What is the best approach to dynamically update the listView? I do not want to use SQLite to store the orders, because only last ten are supposed to be displayed. With a ContentProvider I am not able to store my custom Order object. And if I wrap the ArrayList into a singleton class and use it in the service as well as in the Activity class for the ArrayAdapter, the ListView is not dynamically updated (probably, because the arrayAdapter makes a copy of the arraylist?). Thank you very much.
Filip
use Intent or Bundle
i'm no sure what you mean regarding the ArrayAdapter not being updated, but i can give you a solution we used in my company.
I have a DataMaanger which is a bridge between the Activities and the Networking or SQLite.
The dataMaanger keeps it's data in memory so it's not in DB or on disk. the disadvantage of it is if your app gets killed for lack of memory and reconstructs itself, the dataManager will be empty, which leaves you with two options, either on every Activitie's death or you main task's activities death you serialize your DataManager's data, or if you are not dependant on any previous data, just make arequest again and update the data manager.
I use broadcasts to notify my activities.
To get an access to the DataManager i don't use a sigletone. i use the Application object, you can extend it and in the Manifest.xml give it's name in the tag, then it will be used instead of the regualr Application object.
You can access it later by using getApplication() method in Activity class.