【问题标题】:Can't save multiple custom objects in SharedPreferences?无法在 SharedPreferences 中保存多个自定义对象?
【发布时间】:2016-04-27 07:57:44
【问题描述】:

这是我的问题。我可以保存一个对象,但如果我保存另一个对象,它将删除前一个项目。我正在使用 gson lib 来保存我的项目。经过一些研究,我看到了这个How to use SharedPreferences to save more than one values? 但由于我的自定义对象,我无法使用它,如果我使用 .toString(),我将无法取回我的原始项目。我知道这是用于保存对象的同一个键,它将擦除前一个对象,但我真的不知道每次保存项目时如何提供不同的键。

要添加的代码:

    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();
            }
        }
    });

从其他活动返回的代码:

     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);
    }

感谢您的帮助!顺便说一句,由于它没有节省很多项目,所以我没有使用 sqlite db,干杯!

编辑:我尝试了 Juan Cortés 解决方案,但在取回共享首选项后出现此错误 --> 错误:不兼容的类型:无法将 CustomProduct[] 转换为 List,这是代码

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);
    }

谢谢!

【问题讨论】:

    标签: android gson sharedpreferences adapter


    【解决方案1】:

    例如,作为一个过于简化的应用程序,您可以按如下方式定义一个自定义类(当然,您必须根据您的具体情况对其进行调整)。其概念是创建一个自定义对象数组,将其转换为 json,存储它。一看就明白了。

    代码

    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);
    

    注意事项

    如果数组中已经有一组对象,则需要如上所示扩充数组,使用这些元素 + 要添加的元素创建一个新数组,再次将它们转换为字符串,然后存储它们。一旦这变得太麻烦,您将转向另一种为您的应用保存数据的方式,但只要没有那么多,应该没问题。

    假设

    为了让它工作,我假设您有一个名为 CustomProduct 的自定义对象,其定义如下:

    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+"]";
        }
    }
    

    更新

    用户希望在列表视图中显示结果。您可以定义一个如下所示的自定义适配器以使其工作。让我建议你尽快转向RecyclerView而不是ListView,但首先要解决你遇到的问题,让它发挥作用,然后改进它

    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;
        }
    }
    

    通过将此适配器设置为您的 ListView 并创建布局(仅包含两个具有给定 ID 的文本视图),您将获得以下结果。您可以尝试在第一次运行后删除它创建数据的部分,只保留它获取数据的部分以确保它被持久化。

    【讨论】:

    • 谢谢你的回答,我马上试试,如果我明白了,你的 CustomProduct[] exampleList = new CustomProduct[10];意味着您为收藏夹列表提供了预定义的大小?我也应该把我的 if 块放在外面吗?
    • 在我过于简化的示例中,我确实给了它一个设定的大小,您可能可以对动态大小的东西(例如 ArrayLists)做类似的事情,但我现在无法测试代码,所以这是我能想到的最好的与。
    • 我尝试了你的答案,但之后我在列表视图中显示项目时遇到问题,我的适配器显示错误错误:(88、91)错误:不兼容的类型:无法自定义产品 []转换为 List 编辑:预定义的大小对我来说根本不是问题 :)
    • 你能否给我更多关于你最后评论的细节? @胡安科尔特斯
    • 这是我在这个问题上做的最后一个问题,对不起,但是像这样的问题,我花了比平时更多的时间,没有获得零声誉,没有很多观点,基本上是免费做咨询。查看更新,希望对您有所帮助
    猜你喜欢
    • 2017-12-28
    • 1970-01-01
    • 2018-09-16
    • 2013-02-05
    • 2021-09-30
    • 1970-01-01
    • 1970-01-01
    • 2018-07-31
    • 1970-01-01
    相关资源
    最近更新 更多