Ok, this annoying problem is probably quite familiar, but I don't know what its being called and how to solve it. When I open my app and go to the menu and after a meanwhile, when resuming the app, I loose all my data. It seems that android likes to clean data in order to keep the OS as fast and stable as possible. Which method is recommended in saving data in the internal memory and retrieving it back when any kind of variable is cleaned/null before resuming the app? I tried setSharedPreferences to parse an ArrayList to an Object and parse the Object as a String to save the data and retrieve it, but I get cannot parse Object to String exception. There has to be a better alternative.
Any help will be appreciated.
Edit:
This is how I retrieve and store data:
JSONObject data = (JSONObject) new JSONTokener(result).nextValue();
Helper.RAW_PEOPLE_INFO = data.getJSONArray("people");
Helper.PEOPLE_CONTAINER = new ArrayList<PeopleInfoStorage>();
for( int i = 0; i < Helper.RAW_PEOPLE_INFO.length(); i++ ){
Helper.PEOPLE_CONTAINER.add( new PeopleInfoStorage(Helper.RAW_PEOPLE_INFO.getJSONObject(i)) );
}
I use the PEOPLE_CONTAINER ArrayList to use it later for when I need it. The PEOPLE_CONTAINER ArrayList gets probably cleaned before I resume my application, so can someone help me giving an example on how to store this ArrayList in the internal memory so I can retrieve the data from the internal memory and put it back to the PEOPLE_CONTAINER ArrayList for when it's null again.
It needs to be something like this:
#Override
protected void onPause() {
if( Helper.PEOPLE_CONTAINER != null ){
//save the Helper.PEOPLE_CONTAINER ArrayList to the internal memory
}
super.onPause();
}
#Override
protected void onResume() {
if( Helper.PEOPLE_CONTAINER == null ){
//retrieve the data and store it back to Helper.PEOPLE_CONTAINER ArrayList
}
super.onResume();
}
There are many methods to persist data in your application; I'm not going to go into great detail here, but you should check out these resources:
http://developer.android.com/guide/topics/data/data-storage.html
If you have an array list, it sounds like it might be worth SQLite.
Related
I'm unable to properly fetch a ParseObject that contains a field of type 'Object' : after changing manually the 'Object' field value in the Parse DataBrowser and then fetch the ParseObject from the app, the fetched ParseObject still provide the old value for the 'Object' field, but provide the right new value for the 'String' field.
Here is the sample code I use :
public class MainActivity extends ActionBarActivity {
ParseObject object;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
object = ParseObject.createWithoutData("Test", "tvgTg8jAXz");
}
#Override
protected void onResume() {
super.onResume();
object.fetchInBackground().onSuccess(new Continuation<ParseObject, Object>() {
#Override
public Object then(Task<ParseObject> task) throws Exception {
JSONObject data = task.getResult().getJSONObject("data");
String name = task.getResult().getString("name");
Log.d("OBJECT", data.toString());
Log.d("OBJECT", name);
return null;
}
}).continueWith(new Continuation<Object, Object>() {
#Override
public Object then(Task<Object> task) throws Exception {
if (task.getError() != null) {
Log.e("OBJECT", task.getError().getLocalizedMessage());
}
return null;
}
});
}
}
After I change both 'data' and 'name' fields in the DataBrowser, if 'onResume()' is called without a previous call to 'onCreate()' (after locking/unlocking screen for example) then the logs shows the old value for 'data' and the new value for 'name'.
This is a simple code example to highlight the problem I encounter in a bigger project.
Is this a known issue of the Parse Android SDK ? Is there a workaround ?
Thanks
Now that I learned that you have turned on the local datastore I can come with an, at least partial, answer.
Turning on the local datastore has some side effects. One being that only one instance of each object exists locally. So when you call fetchInBackground the second time, object is already populated with data. The problem then (i think) is that the API no longer override 'complex' types (pointers, objects, arrays), perhaps because it could mess up internal relationships in the data store. Since the fact that the data store will recursively save an object (and pointers) so suddenly swapping a pointer might leave objects 'hanging'. (again, only guessing).
Now I must admit that it still confuses me a bit looking at your code, cause it does not seem that you at any point write your object to the data store, however..
What should work is to unpin the object before 'refreshing' it:
object.unpinInBackground.onSuccess(new Continuation<>{
...
// when done call fetch
});
According to Parse, this is a known issue that they will not fix for now : https://developers.facebook.com/bugs/1624269784474093/
We must use the following methods to retrieve JSON objects/arrays fields from a ParseObject :
getMap() instead of getJSONObject()
getList() instead of getJSONArray()
These methods will return Map and List objects respectively.
I found that managing Map and List in my project instead of JSONObjet and JSONArray is not a problem and is even clearer.
I know, there are plenty of questions in regards to saving/retrieving data on here. I was doing find looking things up on my own and really thought I could manage to find my answers without having to "ask a question", but I began to wonder something that I haven't seen an answer for on here.
MY SITUATION:
Naturally, I'm making an app. Upon closing the app, I want to save a simple array of numbers (0 or 1) or boolean values as it were. Upon starting the app, I want to search for that array, if it exists, and retrieve it for use within the app.
I began placing my code into the activity in which the array would be used. But, I started wondering if I would have to copy/paste the overridden onStop() function into all of my activities? Or do I do it in the main activity and somehow link the other activities.
Basically, no matter what state/activity the app is currently on when the app is closed, I want to be able to save the array of int/bool and open it back up when the app is started.
Maybe I didn't know how to search for what I wanted, so explaining it felt like the right thing to do.
I don't mind doing more searching, but if someone would point me in the right direction at the very least, I'd be extremely grateful.
EDIT: If there's a better way to do what I want than what I described (i.e. using a different state instead of onStop(), for instance), please feel free to throw out ideas. This is my first time actually having to deal with the activities' lifecycles and I'm a bit confused even after looking through the android development tutorials. I really think they're poorly done in most cases.
When you application needs to save some persistent data you should always do it in onPause() method and rather than onStop(). Because if android OS kills your process then onStop() and onDestroy() methods are never called. Similarly retrieve data in onResume() method.
Looking at the purpose you want to fulfill, SharedPreferences is all you want.
The documentation states:
"SharePreferences provides a general framework that allows you to save
and retrieve persistent key-value pairs of primitive data types. You
can use SharedPreferences to save any primitive data: booleans,
floats, ints, longs, and strings. This data will persist across user
sessions (even if your application is killed)."
Use SharedPreference to store small amount of data or use SQLite to store large amount of data.
See this link
http://developer.android.com/guide/topics/data/data-storage.html
Serialize an object and pass it around which is more dependable than shared preferences (had lots of trouble with consistency with shared preferences):
public class SharedVariables {
public static <S extends Serializable> void writeObject(
final Context context, String key, S serializableObject) {
ObjectOutputStream objectOut = null;
try {
FileOutputStream fileOut = context.getApplicationContext().openFileOutput(key, Activity.MODE_PRIVATE);
objectOut = new ObjectOutputStream(fileOut);
objectOut.writeObject(serializableObject);
fileOut.getFD().sync();
} catch (IOException e) {
Log.e("SharedVariable", e.getMessage(), e);
} finally {
if (objectOut != null) {
try {
objectOut.close();
} catch (IOException e) {
Log.e("SharedVariable", e.getMessage(), e);
}
}
}
}
Then use a class to use:
public class Timestamps implements Serializable {
private float timestampServer;
public float getTimestampServer() {
return timestampServer;
}
public void setTimestampServer(float timestampServer) {
this.timestampServer = timestampServer;
}
}
Then wherever you want to write to the variable use:
SharedVariables.writeObject(getApplicationContext(), "Timestamps", timestampsData);
Best way to achieve that is:
create a class. Call it MySettings, or whatever suits you
in this class, define the array of ints / booleans you are going to share, as static. Create getter & setter method (property) to access that (also as static methods)
add a static load() method to MySettings that reads from SharedPreferences. When you launch the app (in your first activity or better in a subclass of Application) call MySettings.load(). This load method sets the array
add a static save() method. Public also. Now you can save from anywhere in you app. This save() method reads the array and writes in SharedPreferences
Code sample:
public class MySettings {
private static List<Integer> data;
public static void load() {
data = new ArrayList<Integer>();
// use SharedPreferences to retrieve all your data
}
public static void save() {
// save all contents from data
}
public static List<Integer> getData() {
return data;
}
public static void setData(List<Integer> data) {
MySettings.data = data;
}
}
Hi guys I have recently come across a really weird problem that I cannot understand. I have tried a few work-arounds, but to no avail.
Basically as the title says, I am saving an ArrayList through the preferences but whenever I access the ArrayList it comes back shuffled.
I am drawing this to a ListView and if I have the ListView looking like:
1
2
3
4
5
6
It will come back looking like
3
2
1
6
5
4
This is my code for the onPause and on onResume
ArrayList<String> todoItems = new ArrayList<String>();
#Override
protected void onPause() {
// TODO Auto-generated method stub
SharedPreferences prefs =
PreferenceManager.getDefaultSharedPreferences(getBaseContext());
SharedPreferences.Editor edit = prefs.edit();
edit.putStringSet("TODOITEMS", new HashSet<String>(todoItems));
edit.commit();
super.onPause();
}
#Override
protected void onResume() {
// TODO Auto-generated method stub
ArrayList<String> returnedItems = new ArrayList<String>
(PreferenceManager.getDefaultSharedPreferences
(getBaseContext()).getStringSet("TODOITEMS",
new HashSet<String>()));
todoItems.clear();
for(int i =0; i < returnedItems.size(); i++){
todoItems.add(returnedItems.get(i));
}
aa.notifyDataSetChanged();
super.onResume();
}
it's because you are using a HashSet to store the values. HashSet doesn't guarantee that the order will be maintained.
you should use a TreeSet instead
check out Hashset vs Treeset
You're not actually saving the todoItems ArrayList and loading it. You're converting the todoItems ArrayList into a HashSet, saving it, then loading it again and re-constructing an ArrayList with it.
In that conversion from ArrayList to HashSet, the orders are not maintained. Checkout this answer on the differences between both: What is the difference between Set and List?
I think that is because you are saving the array to a HashSet.
According to the documentation:
It makes no guarantees as to the iteration order of the set; in particular, it does not guarantee that the order will remain constant over time.
If you want to save a sorted list, I suggest you use SQLiteDatabase.
OR
You can sort the list as you retrieve it from the Shared Preferences. This is not good if the list is very large however.
Collections.sort(returnedItems);
As the previous two answers mention, a HashSet doesn't guarantee preserving order.
One possible solution is to serialize the ArrayList into a String first, save it using putString(), and then load it using getString() and deserialize it.
Check out the second half of this answer to see how to do that: Save ArrayList to SharedPreferences
I want to implement twitter like functionality in my app as when you logged in for the first time you get the data from the server and show it inside listview but if you again open the app without logging out i do not want the app to request the server again for getting the same data so my question is where to store the data that fetched previously so app wont request the server again and for getting the new data i have implemented the refreshable list view so user will get the new data by refreshing the list.
And one more thing is after refreshing i want to store the new data as well to the same place where previous data was saved and i want to store only the 20 items to prevent the memory overflow . please help someone.
I have an arraylist ArrayList> fetch where i am storing the data while fetching from the server.
The server must be returning the information in JSON or XML format, simply put it in shared preferences and retrieve/show later based on a few internal flags.
For example, here's a sample code to store stuff in shared preferences:
private void writeStrToPreferences(String strKey, String str){
if(strKey == null) return;
if(str == null) return;
if(str.length() <= 0) return;
SharedPreferences.Editor ed = getSharedPreferences(strKey, 0).edit();
ed.putString(strKey, str);
ed.commit();
}
Reading back will also be similar and simple
private String readStrFromPreferences(String strKey){
if(strKey == null)return "NA";
if(strKey.length() <= 0) return "NA";
return getSharedPreferences(strKey, 0).getString(strKey, "NA");
}
For more, check documentation here:
http://developer.android.com/reference/android/content/SharedPreferences.html
I am trying to restore an array of Objects from a savedInstanceState. I added each one to the Bundle individually here: (rhythm is the array of Objects)
#Override
public void onSaveInstanceState(Bundle outState){
outState.putInt("numParts",rhythm.length);
for(int index = 0;index<rhythm.length;++index){
outState.putSerializable(""+index,rhythm[index].beat);
}
super.onSaveInstanceState(outState);
}
When the onRestoreInstanceState() method is called, I try to assign my rhythm array with the Objects from the Instance State here: (it isn't null)
#Override
public void onRestoreInstanceState(Bundle savedInstanceState){
rhythm = new Part[savedInstanceState.getInt("numParts")];
for(int index = 0; index<rhythm.length;++index){
Object middleMan =savedInstanceState.getSerializable(""+index);
if(middleMan==null){
System.out.println("It's null...");
}
rhythm[index]=(Part) middleMan;
}
}
It throws a ClassCastException when I parse to a Part every time. Part implements Serializable. Why is it not allowing me to parse? Will I need to do custom serialization?
Please help!
I am guessing that Part is a type that you have created? So instead of treating Part as an array
rhythm = new Part[savedInstanceState.getInt("numParts")];
You want to instantiate a new Part object like so:
rhythm = new Part(savedInstanceState.getInt("numParts"));
Other assumptions:
rhythm is a member variable
The constructor for Part takes a single integer
Okay I just did it as the whole array and it worked... I don't really know why, but it did. Thanks for giving me the idea to just pass the whole array. #Error 454