How to store listView.onSaveInstanceState into SharedPreferences? - android

I'm using a listView and wants to restore/ resume the listView item/ state from where I had left (even after app closes).
For this purpose I'm using
Parcelable state = listView.onSaveInstanceState();
the state is of Parcelable type because it returns result in parcelable type also while on restoring listView using
listView.onRestoreInstanceState(state);
it needs Parcelable type data as a parmeter.
It works perfectly (using static variable) if user didn't closes the app.
But I want to save this state data into SharedPreferences that will help the user to restore the listView even after closing the app.
I don't know how to store this state data into SharedPreferences. Please help me to solve this issue.
I also have tried this solution
How Android SharedPreferences save/store object
but it didn't solved my problem. The app is crashing on
Parcelable obj = gson.fromJson(json, Parcelable.class);
So, Please don't duplicate my question, If you know the solution just answer it.

I assume that your listview has an adapter that contains your required data so you can save that data somewhere (e.g. in sharedpreferences) instead of whole view's parcelable, e.g. if your adapter data is an ArrayList<ModelA> you can do something like this:
if ( listview.getAdapter() instanceof MyAdapter){
MyAdapter adapter = (MyAdapter) listview.getAdapter();
SharedPreferences.Editor editor = prefs.edit();
editor.putString( "adapterdata" , gson.toJson(adapter.getData()));
editor.commit(); //or editor.apply()
}
and when you want to retrieve the data
String dataJson = prefs.getString( "adapterdata" , "");
ArrayList<ModelA> data = gson.fromJson( dataJson, new TypeToken<ArrayList<ModelA>>(){}.getType());
if ( data != null ){
//set data to your listview, also it's logical to delete retrieved data from sharedpreferences
SharedPreferences.Editor editor = prefs.edit();
editor.remove("adapterdata");
editor.commit();
}

Related

Getting data from sharedPreference to a specific activity

Is it possible to get a sharedprefence data from MainActivity_A and fetch it only to MainActivity_B and the other activities like MainActivity_C and MainActivity_D cannot access the data that has been fetched to MainActivity_B?
Well It totally depends on you wheather you wanna get that data or not..once you store data in shared preference with key then just get that data in the specific activity you want Thats It !!
For Example in Activity X you save the Shared Preference value like this
public static final String SHARED_PREFS = "sharedPrefs";
SharedPreferences sharedPreferences = getSharedPreferences(SHARED_PREFS,MODE_PRIVATE);
SharedPreferences.Editor editor=sharedPreferences.edit();
editor.putString("Key",Value);
Then in Activity A you want to use this value then you can do it like this
SharedPreferences pref;
pref = getSharedPreferences(SHARED_PREFS, Context.MODE_PRIVATE);
String Value = pref.getString("Key");
In This way the value will be stored in variable String
And if you don't want the value in other activity then just don't call it !!

Logic behind storing a max number of user favorites to SharedPreferences

I'm wanting to store a number of different user favorites (in this example a max of 5) in sharedpreferences.
The user will be able to add and delete these favorites from within the app.
I'm having trouble getting my head around how to achieve this (I assume some sort of looping is needed).
The gist of what I'm trying to do when a user adds a new favorite:
//init prefs
public static final String PREFS_NAME = "PREFS";
SharedPreferences sharedPreferences = null;
SharedPreferences.Editor sharedPreferencesEditor;
//onCreate
sharedPreferences = getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);
//method called when user adds new favorite
public void addFavorite(String fav) {
//int i = 0;
//int maxFavs = 5;
//check how many favorites are already stored in shared prefs, if any (is it under maxFavs?)
//if over maxFavs, display error
Toast.makeText(getApplicationContext(),"Favorite added",Toast.LENGTH_SHORT).show();
//else continue
//upon finding available favorite 'space' (less than permitted maxFavs), add to favorites in shared prefs
sharedPreferencesEditor = sharedPreferences.edit();
sharedPreferencesEditor.putString("fav_" + i, fav);
sharedPreferencesEditor.apply();
}
Am I getting the right idea here, or is there a better way to do what I'm intending to do? Hopefully it's clear from the above.
Store favorite count in preferences as an int and read & update it as needed. Also it would be better if you store favorites in preferences as (key : favoritedItemId, value boolean)
Even better: Use a proper local database for situations like this. Preferences is a primitive key value type storage intended for simplier cases like storing a users light mode preference.
Gave up and created a simple database following the example here:
https://inducesmile.com/android/android-sqlite-database-example-tutorial/
Still, if anyone has a solution I'd be interested to see!

Saving and restoring ListView with Custom List Adapter

I'm currently using a custom list adapter and modifying the rows of the listview at runtime (changing text, buttons etc).
I want to find a way to save/restore the changes made to the listview at runtime when I start another fragment and then come back to the fragment containing the listview.
Currently the listview is being reloaded every time and all the runtime changes are lost.
The following shows how I am setting the list adapter.
public void setAdapterToListView(ArrayList<item> list) {
ItemList = list;
ItemAdapter adapter = new MenuItemAdapter(list, getActivity(), this);
ItemListView.setAdapter(adapter);
}
I am then using a custom list adapter to make the changes (mentioned above) at runtime. Here's a snippet of how I am changing things at runtime:
if (holder.qty.getText().toString().equals("Qty")) {
relativeLayout.setBackgroundColor(row.getResources().getColor(R.color.navDrawerL ightBlue));
holder.qty.setText("1");
holder.qty.startAnimation(anim);
holder.removeItem.setBackgroundResource(R.drawable.remove_item_red);
holder.removeItem.setEnabled(true);
...
Is there a recommended way to approach this issue?
Adapter
You will want your custom adapter to implement some sort of getter for it's internal data. For instance
public ArrayList<YourDataType> getList() {
return new ArrayList<YourDataType>(mAdapterData);
}
Activity
Then in your activity/fragment, you'll need to save and restore that data.
private static final String STATE_LIST = "State Adapter Data"
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putParcelableArrayList(STATE_LIST, getAdapter().getList());
}
While there is an onRestoreInstanceState() method you could override, I typically restore during onCreate(). Usually more convenient to when other things are getting instantiated. Either or is viable.
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//If restoring from state, load the list from the bundle
if (savedInstanceState != null) {
ArrayList<YourDataType> list = savedInstanceState.getParcelableArrayList(STATE_LIST);
ItemAdapter adapter = new MenuItemAdapter(list, getActivity(), this);
} else {
//Else we are creating our Activity from scratch, pull list from where ever you initially get it from
ArrayList<YourDataType> list = getInitData();
ItemAdapter adapter = new MenuItemAdapter(list, getActivity(), this);
}
}
YourDataType
You didn't mention what YourDataType was but I'm assuming it's a custom class. In order to work with the bundled savedstate, it must implement Parcelable. Android's dev link on Parcelable and a StackOverFlow post explaining how to write your own custom class with Parcelable.
Update
Depending on what you are doing with the fragment will dictate if the onSavedInstanceState() method will be called. From the way your question is asked, I'm assuming you are pushing one fragment onto the backstack to load another on top. Then hitting the back button will reloaded that fragment from the backstack...and pass along the bundled state to reload from.
Of course that is just one of many scenarios. It's perfectly possible for the fragment in question to only perform onPause() followed by onStop()...then when redisplaying the fragment, only seeing it do onStart() followed by onResume(). In this case, there would not be a saved state because the fragment was never fully destroyed, so there is nothing to restore. It should be in the same state. If it's not and instead you are seeing it reload the initial data...then you are probably reloading the initial data in or after onStart(). You'll want to move all that initializing data to onCreate() instead.
Another possible case is that you completely destroy the fragment without ever putting it on the backstack. Re-initializing it would not have a saved state to pull from. If you wanted to "restore" this fragment back to the state beforehand, then you can not rely upon onSavedInstanceState(). You will need to persist that information manually somewhere in memory, to disk, or a DB yourself. Then pull from it accordingly.
Life cycles with fragments are unfortunately really complex and depend greatly on usage and even between the support library vs native fragments.
After doing some reading/research I ended up solving this by saving the adapter data to Saved Preferences by using Gson (https://code.google.com/p/google-gson/).
I used Gson to first convert my array of objects into Json and then stored the Json strings in the Saved Preferences.
Subsequently I was able to retrieve these as required and read the Json into Java objects again, store these in an array list and pass this to my listview adapter.
Here's a brief overview of the process for anyone who is looking to do something similar.
Saving to Shared Preferences:
SharedPreferences settings;
Editor editor;
settings = c.getSharedPreferences(PREFS_NAME,Context.MODE_PRIVATE);
editor = settings.edit();
Gson gson = new Gson();
String ItemsJson = gson.toJson(list);
editor.putString(categoryId, ItemsJson);
editor.apply();
Reading from Shared Preferences:
if (settings.contains(categoryId) {
String jsonItems = settings.getString(categoryId, null);
Gson gson = new Gson();
Item[] favoriteItems = gson.fromJson(jsonItems, Item[].class);
list = Arrays.asList(favoriteItems);
ItemsFromSharedPrefs = new ArrayList<>(list);
AllCategories.addAll(ItemsFromSharedPrefs);
} etc...

Problems in storing the listview data

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

Is it better to pass data via intent or query the database when needed?

I am just wondering what would be the better way to handle data in several activities in android.
Say I had two activities, A and B, that hold some views. First I load some data from a SQL database and inflate the views in A. Now, I want to start activity B, which uses the same set of data as A did.
Is it better to pass the data via Intent (putExtra()) and then inflate the views or is it better to query the database again and then inflate.
I am not sure about that, because both approaches seem to have their disadvantages:
Querying the database takes more time /more resources
Putting extra data to the intent makes it more complex, because of putting and getting the data (especially when working with more activities)
Can someone give me some advice on what is the best practice?
As compare to DB Query use Intent.
And another way is, use one common class which will holds your data temporary.
There is various way to pass and get data. It is more useful to use Intent than DB query.
But there is another useful way is shared prefernce. Through which you can create,edit, delete data as well as can fetch data from any of the activity.
To create or edit shared preference:
String share_pref_file = "your_file_name";
SharedPreferences prefs1 = getSharedPreferences(
share_pref_time_file, Context.MODE_PRIVATE);
SharedPreferences.Editor editor1 = prefs1.edit();
editor1.putString("your_data", data); //data is your variable
editor1.commit();
To fetch data:
String share_pref_file = "your_file_name";
SharedPreferences prefs = getSharedPreferences(share_pref_file,
Context.MODE_PRIVATE);
String strJson = prefs.getString("your_data", "");
To delete:
String share_pref_file = "your_file_name";
SharedPreferences prefs1 = getSharedPreferences(
share_pref_file, Context.MODE_PRIVATE);
SharedPreferences.Editor editor = prefs1.edit();
editor.remove(share_pref_file);
editor.clear();
editor.commit();

Categories

Resources