Can't save multiple custom objects in SharedPreferences? - android

Here is my issue. I can save an object, but if I save another object, it will erase the previous item. I'm using gson lib to save my items. After some researches I've seen this How to use SharedPreferences to save more than one values?
But I can't use it because of my custom objects, if I use .toString(), I will not be able to get back my original item. I know that's it's the same key used to save object that will erase the previous one but I dont really know how to give a different key every time I will save an item.
Code to add :
addFav.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
if (currentProduit.getIsAdded() ==0) {
SharedPreferences.Editor prefsEditor = mPrefs.edit();
Gson gson = new Gson();
String myJson = gson.toJson(currentProduit);
Log.i("INFO", "Value of saved data" + myJson);
prefsEditor.putString("myproduct", myJson);
prefsEditor.apply();
Toast.makeText(getApplicationContext(), "Data saved !", Toast.LENGTH_SHORT).show();
addFav.setText(R.string.delete_fav);
currentProduit.setIsAdded(1);
} else {
addFav.setText(R.string.add_fav);
currentProduit.setIsAdded(0);
SharedPreferences.Editor editor = mPrefs.edit();
editor.remove("myproduct").apply();
Toast.makeText(getApplicationContext(), "Data removed !", Toast.LENGTH_SHORT).show();
}
}
});
Code to get back from other activity:
String myJson = mPrefs.getString("myproduct", "");
Log.i("INFO", "Value of loaded data" + myJson);
if (myJson.isEmpty() && favProductList.isEmpty()) {
listview_R.setAdapter(null);
Log.i("INFO", "No items");
title.setText(getString(R.string.fav));
} else if (myJson.isEmpty() && favProductList != null) {
myCustomAdapterVersionR = new CustomAdapter_VersionR(getApplicationContext(), favProductList);
listview_R.setAdapter(myCustomAdapterVersionR);
} else {
Product savedProduct = gson.fromJson(myJson, Product.class);
favProductList.add(savedProduct);
Log.i("INFO", "Favorite was added");
myCustomAdapterVersionR = new CustomAdapter_VersionR(getApplicationContext(), favProductList);
listview_R.setAdapter(myCustomAdapterVersionR);
}
Thanks for helping ! Btw, since it's not saving a lot of items, I didnt use sqlite db, cheers !
EDIT: I tried Juan Cortés solution, but I have this error after getting back the shared preferences --> error: incompatible types: CustomProduct[] cannot be converted to List, here is the code
if (fromPrefs.isEmpty() && favProductList.isEmpty()) {
listview_R.setAdapter(null);
Log.i("INFO", "No items");
title.setText(getString(R.string.fav));
} else {
//Product savedProduct = gson.fromJson(fromPrefs, Product.class);
//favProductList.add(savedProduct);
//Get the Object array back from the String `fromPrefs`
CustomProduct[] reInflated = gson.fromJson(fromPrefs,CustomProduct[].class);
Log.i("INFO", "Favorite was added");
myCustomAdapterVersionR = new CustomAdapter_VersionR(getApplicationContext(), reInflated); //error
listview_R.setAdapter(myCustomAdapterVersionR);
}
Thanks !

As an overly simplified app for example, you could define a custom class as follows (of course you'll have to adapt it to your particulars). The concept is create an array of custom objects, convert it to json, store it. It's really straightforward once you see it.
The code
Gson gson = new Gson();
//Create an array to work with it, dummy content
CustomProduct[] exampleList = new CustomProduct[10];
for(int i=0;i<10;i++){
exampleList[i] = new CustomProduct("string","number:"+i);
}
//Get a String representation of the objects
String forStoring = gson.toJson(exampleList);
//HERE you can store and retrieve to SharedPreferences
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
prefs.edit().putString("myarrayofcustomobjects", forStoring).commit();
//Get the string back from the SharedPreferences
String fromPrefs = prefs.getString("myarrayofcustomobjects","");
//Get the Object array back from the String `fromPrefs`
CustomProduct[] reInflated = gson.fromJson(fromPrefs,CustomProduct[].class);
Notes
If you already have a set of objects in an array, you'll need to inflate the array as shown above, create a new array with those elements + the one you want to add, convert them to a string again, and store them. Once this becomes too much of a hassle, you'll move to another means of persisting data for you app, but for as long as there are not that many, it should be ok.
Assuming
To get this to work, I'm assuming you have a Custom object named CustomProduct with the following definition:
public class CustomProduct {
String field1,field2;
public CustomProduct(String field1, String field2){
super();
this.field1 = field1;
this.field2 = field2;
}
#Override
public String toString() {
return "CustomProduct [field1="+field1+",field2="+field2+"]";
}
}
Update
User wants to show the results in a listview. You can define a custom adapter like the following to get it to work. Let this be the time for me to advise you to soon move towards RecyclerView instead of ListView but first tackle the problem you have, make it work, then improve upon it
public class CustomAdapter extends BaseAdapter{
private CustomProduct[] mProducts;
private LayoutInflater mInflater;
public CustomAdapter(Context context, CustomProduct[] products){
mProducts = products;
mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
public int getCount() {
return mProducts.length;
}
public CustomProduct getItem(int i) {
return mProducts[i];
}
public long getItemId(int i) {
return i;
}
public View getView(int i, View convertView, ViewGroup parent) {
//Purposely not doing view recycling for sake of clarity
View row = mInflater.inflate(R.layout.custom_row,parent,false);
//Set the data from the row
((TextView)row.findViewById(R.id.field1)).setText(getItem(i).field1);
((TextView)row.findViewById(R.id.field2)).setText(getItem(i).field2);
//Return the view
return row;
}
}
By setting this adapter to your ListView and creating the layout (which simply consists in two textviews with the given ids) you will get the following result. You can try removing the part where it creates the data after it's run the first time and leaving only the part where it fetches the data to ensure it's persisted.

Related

How we can retrieve the data of the checkboxes in another activity in a text view

This is the activity where I defined the checkboxes and Array list.
I have save the result in the arraylist and want to display the same arraylist in another activity.
public ArrayList<String> Result;
Result = new ArrayList<>();
public void statuscheck(){
bcg.setOnClickListener(v -> {
if(bcg.isChecked()){
Result.add("BCG(Bacillus Calmette and Guérin)");
}
else {
Result.remove("BCG(Bacillus Calmette and Guérin)");
}
});
bopv0.setOnClickListener(v -> {
if(bopv0.isChecked()){
Result.add("b Oral Polio vaccine(bOPV)-0 ");
}
else {
Result.remove("b Oral Polio vaccine(bOPV)-0 ");
}
});
hepatitis0.setOnClickListener(v -> {
if(hepatitis0.isChecked()){
Result.add("Hepatitis B birth dose ");
}
else {
Result.remove("Hepatitis B birth dose ");
}
});
}
the activity where I want to show the arraylist in a text view
TextView vac_result;
ArrayList<String> vc_Res;
vac_result = findViewById(R.id.vac_result);
vac_result.setEnabled(false);
vc_Res = vaccineone.Result;
StringBuilder stringBuilder = new StringBuilder();
for(String s : vc_Res)
stringBuilder.append("\n");
vac_result.setText(stringBuilder.toString());
vac_result.setEnabled(true);
There are many ways to achieve what you want. You can either pass your data as a Bundle when you're trying to call startActivity() or use a static global variable across your application.
The snippet below will demonstrate how to use a static variable:
class Example {
public static ArrayList<String> Result = new ArrayList<>();
}
Fill the static arraylist with your data and simply get the data in the other activity.
Save the "Result" ArrayList with SharedPreferences and in the other activity load the data before trying to work with it.

override arraylist on shared preferences

I'm saving an arraylist on shared preferences but when i add something new to this array it deletes the old one and displays only the new one.
Here is the save and load array from shared preferences
//SHARED PREFERENCES Save ArrayList
public boolean saveArrayList(SharedListFood list) {
SharedPreferences.Editor editor = prefs.edit();
Gson gson = new Gson();
String json = gson.toJson(list.getMlist()); //put in json the list from my model(SharedFoodList) which is the list i provide(itemsAdded)
editor.putString("testShared", json);
return editor.commit(); // This line is IMPORTANT !!!
}
//SHARED PREFERENCES Load ArrayList
public ArrayList<String> getArrayList() {
ArrayList<String> loadArrayList;
Gson gson = new Gson();
String json = prefs.getString("testShared", null);
Type type = new TypeToken<ArrayList<String>>() {
}.getType();
loadArrayList = gson.fromJson(json, type);
return loadArrayList;
}
I add the item here.
searchList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
searchMessage = searchList.getItemAtPosition(position).toString(); //searchMessage gets the value of the pressed item in list
if(searchMessage.contains("two")){
Log.d("alekos","tak"+searchMessage);
}
Toast.makeText(AddFood.this, "" + searchMessage, Toast.LENGTH_SHORT).show();
itemsAdded.add(searchMessage);// made it static so it is created here but displayed in the AddFoodBasket.java
sharedArray=new SharedListFood(itemsAdded);
boolean isSuccess= sharedArrayPreferencesHelper.saveArrayList(sharedArray); //sends itemsAdded to saveArrayList in shared preferences
if (isSuccess) {
Toast.makeText(getApplicationContext(),"Personal information saved", Toast.LENGTH_LONG).show();
} else {
Toast.makeText(getApplicationContext(),"Personal information NOT", Toast.LENGTH_LONG).show();
}
}
});
Where itemsAdded is the arraylist i want to add each time
As per my understanding,
1. you have written SharedPreferences.Editor inside saveArrayList().
2. On every single time this method called, you create a new Editor and it replaces the
previous one.
3. SharedPreferences stores in key-value pair and you are storing data in the same key
every time. (It Replaces previous values with new ones)
4. Your code might be correct for data but the flow is wrong. Try to work on your code-
flow.
Hope it helps. :)

Retrieve Arraylist from Shared Preferences

I am working on shared Preferences. Basically, I am saving ArrayList to shared preferences which are working fine. Now I want to retrieve the ArrayList from Shared preferences but I am getting null. ArrayList is retrieving from preferences and also showing it's size. but data is not being set to string. How I retrieve the ArrayList from shared Preferences.
here is my code
public void saveRootCategory(List<Category> categories){
preferences = mCtx.getSharedPreferences(SHARED_PREF_NAME, MODE_PRIVATE);
editor = preferences.edit();
editor.putInt("RootCategory",categories.size());
for (int i=0;i<categories.size();i++){
setData(categories.get(i));
}
editor.apply();
}
public void setData(final Category category){
categoryId = category.getId();
categoryName = category.getCategoryName();
editor.putInt("CategoryId",categoryId);
editor.putString("CategoryName",categoryName);
}
public ArrayList<String> getRootCategoy() {
preferences = mCtx.getSharedPreferences(SHARED_PREF_NAME, MODE_PRIVATE);
ArrayList<String> rootCategories = new ArrayList<>();
rootCategories.clear();
int size = preferences.getInt("RootCategory", 0);
for(int i=0;i<size;i++) {
int Id = preferences.getInt("CategoryId" + i,0);
String name = preferences.getString("CategoryName" + i ,"");
rootCategories.add(String.valueOf(Id));
rootCategories.add(name);
}
return rootCategories;
}
I used to have the same null problem
Here's how I solved it
I have an arrayList named language
language = new ArrayList<String>
I had to add everything the user writes on the edittext on button click not repeating any redundant value
if(!language.contains(value)) {
language.add(value);
}
To save this arraylist I created a hashSet
Set<String> set = new HashSet<String>();
and save all of them onPause
set.addAll(language);
.putStringSet("yourKey", set);
.commit();
and retrive it back to language array list onCreate
prefs=this.getSharedPreferences("yourPrefsKey",Context.MODE_PRIVATE);
edit=prefs.edit();
set = prefs.getStringSet("yourKey", null);
language = new ArrayList<String>(set);
edit.remove("yourKey").commit();
remember to remove everytime or it will again create null
You are missing the index in setData. Change it to
public void setData(final Category category, int index){
categoryId = category.getId();
categoryName = category.getCategoryName();
editor.putInt("CategoryId" + index, categoryId);
editor.putString("CategoryName" + index, categoryName);
}
As you are trying to save the ArrayList into the share preference.
I Suggest you can use PaperDB Library.
Which is very fast and directly save your ArrayList same as preference doing.
You can also use it to store the Primitive datatypes and model class directly.
Note: It also reduces the code lines.
Add some breakpoints on setData() -> editor.putInt("CategoryId",categoryId); and debug your code are necessary.
BTW, it seems that there's no difference you call either editor.apply() or editor.commit() running on API 9 or above devices.
Replace your both methods with these:
public void saveRootCategory(List<Category> categories){
preferences = mCtx.getSharedPreferences(SHARED_PREF_NAME, MODE_PRIVATE);
editor = preferences.edit();
editor.putString("RootCategory",new Gson().toJson(categories));
editor.apply();
}
public ArrayList<Category> getRootCategoy() {
preferences = mCtx.getSharedPreferences(SHARED_PREF_NAME, MODE_PRIVATE);
String data = preferences.getString("RootCategory","");
return new Gson().fromJson(data, new TypeToken<List<Category>>(){}.getType());
}
No third party library needed use Gson(inbuilt) library which can easily do what you want to achieve.
public void setData(final Category category)
The method use the same key("CategoryId", "CategoryName") to save every item in the list.
However, you use "CategoryId" + index to get the value from SharedPreference.
Obviously, you can never get the right answer in this way...
#Murat's answer correct the method, and it can work well.
But I don't think it's a good way to save a List. If you do want to use SP to save Lists, I suggest Gson or any other way to translate your object into String first. It will work better.

How to autoIncrement values and save them in a List in Android

I want to save every scanned item in a list with a name "Draft"+serial Number,
example: when 1st item is selected it will be saved as Draft1, when
2nd item is scanned it will be saved as Draft2 and so on..
I tried this with sharedPrefrences but it doesn't help me.
what else approach should I go for?
Here's my code:
btn_save_draft.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
try{
int countt = 0;
if (!list.isEmpty()) {
if(arrayAdapter==null || arrayAdapter.getCount()==0){
if(editor!=null){
System.out.println("==clear SharedPref data==");
sPrefs.edit().clear().commit();
}
}
editor = getPreferences(MODE_PRIVATE).edit();
int defaultValue =
getPreferences(MODE_PRIVATE).getInt("count_key",countt);
System.out.println("===def==="+defaultValue);
++defaultValue;
getPreferences(MODE_PRIVATE).edit().putInt("count_key",defaultValue)
.commit();
countt =
getPreferences(MODE_PRIVATE).getInt("count_key",countt);
showSaveDraftDialog(countt);
}else {
Toast.makeText(mActivity, "Try again",
Toast.LENGTH_SHORT).show();
}
}catch(Exception e){
e.printStackTrace();
}
}
});
When ever you need to save the name, you can do something like:
item.setName("draft "+i++);
where i is a static global variable and item is the type of object you need to put in Draft. Create a separate class for that object, define a parameter called name and generate its getter and setter methods. Hope it might help.

Save a ListView layout on Android?

I have a ListView containing news from RSS feeds in MainActivity, the problem is I have to stream the RSS feeds everytime I open the app because the items of the ListView are destroyed when I close the app.
I understand I can save it in SQLite temporarily, but is there a more simple way to save the ListView layout just so it would still be there next time I open the app?
Another option is to use SharePreferences and Gson to convert your datasource for the list view into a string for storage and then when the app is re-opened you can rebuild the list view with the stored data fairly quickly. I do something similar in one app where the data source for my list view is a ArrayList of LinkedHashMap items, so this would be the two methods for converting the ArrayList to a String and then back to an ArrayList when needed
public static String ArrayListToString(ArrayList<LinkedHashMap> list) {
return gson.toJson(list);
}
public static ArrayList<LinkedHashMap> StringToArrayList(String input) {
Type collectiontype = new TypeToken<ArrayList<LinkedHashMap>>(){}.getType();
ArrayList<LinkedHashMap> list = gson.fromJson(input, collectiontype );
return list;
}
I would also then suggest storing a timestamp so you can check if the stored list should be displayed or if an updated list needs to be retrieved
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
listView = (ListView)findViewById(R.id.clientListView)
...whatever other setup you want to do here
CheckTimeStamp();
}
public static void CheckTimeStamp() {
String timeStamp = preferences.getString("keyClientTimeStamp", "");
Calendar calendar = Calendar.getInstance();
Date date = calendar.getTime();
String currentTime = HelperClass.GetSimpleDateFormat(date);
if (currentTime.equals(timeStamp)) {
String storedString = preferences.getString("keyStoredClients", "");
clientArrayList = HelperClass.StringToArrayList(decryptedArray);
//the setupView method is where I take my ArrayList
//and add it to my ListView's Adapter
SetupView();
}
else {
SharedPreferences.Editor editor = preferences.edit();
editor.putString(Constants.keySalesTimeStamp, currentTime);
editor.apply();
//for me this is a web service that get's a list of clients,
//converts that list to a String to store in SharedPreferences
//and then calls SetupView() to add the list to the ListView Adapter
GetClientList();
}
}
Hmm, I would use Volley library for caching requests, I guess it very simple: you do request and next time first of all get it from cache. You don't have to explicitly save and describe a model for storing data for this case.
Below, I gave the example of how it might look:
public class RSSProvider {
private final RequestQueue mRequestQueue;
// ...
private RSSProvider(Context context) {
mRequestQueue = Volley.newRequestQueue(context.getApplicationContext());
}
// ...
public void getSomething(final Response.Listener<String> responseListener, final Response.ErrorListener errorListener) {
if (mRequestQueue.getCache().get(<URL>) != null) {
responseListener.onResponse(new String(mRequestQueue.getCache().get(<URL>).data));
} else {
StringRequest request = new StringRequest(Request.Method.GET, <URL>, responseListener, errorListener);
request.setShouldCache(true);
mRequestQueue.add(request);
}
}
// ...
}

Categories

Resources