【问题标题】:How to effectively store checkbox values in Custom BaseAdapter如何在自定义 BaseAdapter 中有效地存储复选框值
【发布时间】:2014-08-15 20:02:41
【问题描述】:

在过去的两周里,我一直在努力寻找一种解决方案,以便在我退出并打开应用程序时将我的复选框值存储在我的每个列表视图项旁边。本质上,我有一个自定义 BaseAdapter 类,它使用用户手机上安装的应用程序填充列表视图,并在每个安装的应用程序旁边有一个复选框。当我向下滚动复选框时,状态保持不变;但是,当我单击返回或退出并返回时,它不会保持不变。

我几乎以所有可能的方式使用了 SharedPreferences。我的最后一种方法是使用 for 循环为每个循环创建一个 SharedPreference 并在 for 循环中恢复布尔值,并在 if 和 else 语句中存储布尔值 true 和 false(分别用于检查和未检查)。

这是我使用 SharedPreferences 的 BaseAdapter 类的代码:

package com.ibc.android.demo.appslist.app;

import android.app.Activity;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.graphics.drawable.Drawable;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.CheckBox;
import android.widget.TextView;

import com.spicycurryman.getdisciplined10.app.R;

import java.util.List;

//

public class ApkAdapter extends BaseAdapter {

    //Pastebin link:  http://pastebin.com/LGRicg4U , http://pastebin.com/c4WfmhMK , http://pastebin.com/gFuuM4dY, http://pastebin.com/4Q7EP9G4
    // http://pastebin.com/Te2g072w,  http://pastebin.com/NLT5iUiA ,

    SharedPreferences sharedPrefs;
    List<PackageInfo> packageList;
    Activity context;
    PackageManager packageManager;
    boolean[] itemChecked;

    String PACKAGE_NAME;

    public ApkAdapter(Activity context, List<PackageInfo> packageList,
                      PackageManager packageManager) {
        super();
        this.context = context;
        this.packageList = packageList;
        this.packageManager = packageManager;
        itemChecked = new boolean[packageList.size()];

    }


    private class ViewHolder {
        TextView apkName;
        CheckBox ck1;
        TextView packageName;
    }

    public int getCount() {
        return packageList.size();
    }

    public Object getItem(int position) {
        return packageList.get(position);
    }

    public long getItemId(int position) {
        return 0;
    }

    @Override
    public View getView(final int position, View convertView, ViewGroup parent) {
        final ViewHolder holder;

        LayoutInflater inflater = context.getLayoutInflater();

        if (convertView == null) {
            convertView = inflater.inflate(R.layout.installed_apps, null);
            holder = new ViewHolder();

            holder.apkName = (TextView) convertView
                    .findViewById(R.id.appname);
            holder.ck1= (CheckBox)convertView
                    .findViewById(R.id.checkBox1);



            convertView.setTag(holder);
            //holder.ck1.setTag(packageList.get(position));

        } else {

            holder = (ViewHolder) convertView.getTag();
        }



        // ViewHolder holder = (ViewHolder) convertView.getTag();
        PackageInfo packageInfo = (PackageInfo) getItem(position);



        Drawable appIcon = packageManager
                .getApplicationIcon(packageInfo.applicationInfo);



        // Make sure to define it again!
        PACKAGE_NAME = packageInfo.packageName;


        final String appName = packageManager.getApplicationLabel(
                packageInfo.applicationInfo).toString();
        appIcon.setBounds(0, 0, 80, 80);
        holder.apkName.setCompoundDrawables(appIcon, null, null, null);
        holder.apkName.setCompoundDrawablePadding(15);
        holder.apkName.setText(appName);


        holder.ck1.setChecked(false);


        if (itemChecked[position])
            holder.ck1.setChecked(true);
        else
            holder.ck1.setChecked(false);

        Log.d("just loaded??", PACKAGE_NAME);


        Log.d("just loaded 2?", appName+position);



        // CHANGE UP EVERYTHING! MAKE THIS SHIT WORK, TIGGA!


        for(int i= 0; i<packageList.size(); i++){
            sharedPrefs = context.getSharedPreferences(String.valueOf(i), Context.MODE_PRIVATE);
            holder.ck1.setChecked(sharedPrefs.getBoolean(String.valueOf(i),false));


        }

        holder.ck1.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {


                SharedPreferences.Editor editor = context.getSharedPreferences(String.valueOf(position), Context.MODE_PRIVATE).edit();

                if (holder.ck1.isChecked()) {
                    itemChecked[position] = true;
                    holder.ck1.setChecked(true);
                    Log.i("This is", " checked: " + position);
                    editor.putBoolean(String.valueOf(position), true);
                    Log.d("put true", appName+position);

                    editor.apply();

                } else {
                    itemChecked[position] = false;
                    holder.ck1.setChecked(false);
                    Log.i("This is", " not checked: " + position);
                    editor.putBoolean(String.valueOf(position), false);
                    Log.d("put false", appName+position);

                    editor.apply();

                }

            }


        });

        return convertView;

    }




}

我还创建了一个 DatabaseHandler 类和 Object 类,用于使用 SQLite 数据库来存储我的复选框值,而不是在使用 SharedPreferences 存储它失败后。

这里是 pastebin 链接,所以我不会阻塞帖子:

DatabaseHandler 类:http://pastebin.com/NzKhBiZ3

对象类:http://pastebin.com/Jp3BLXba

我知道有很多关于使用自定义适配器/列表视图以及使用 SQLite 和 SharedPreferences 保存复选框和按钮状态等的帖子、博客和链接,但我向你保证,我已经完成了数周的研究,但我无法找到适合我的具体情况的东西。

一些例子:

Saving State of the checkbox in a custom list view with Checkboxes

http://blog.csdn.net/qu213/article/details/9289349

在我的特定情况下,最佳选项是什么?在我的情况下,我将如何生成解决方案以成功保存每个已安装的应用程序列表视图项目旁边的复选框状态,这些状态将在我退出应用程序后保存,并且重新输入?一些代码真的很有帮助。

感谢您的宝贵时间。

如果您需要我包含任何 xml 文件,请告诉我。

【问题讨论】:

    标签: java android sqlite android-listview sharedpreferences


    【解决方案1】:

    我想我可能已经解决了您的问题。请尝试此代码,看看它是否有效。

     for(int i= 0; i<packageList.size(); i++){
                PACKAGE_NAME = packageInfo.packageName;
    
                sharedPrefs = context.getSharedPreferences(PACKAGE_NAME, Context.MODE_PRIVATE);
                Log.d("just got sharedpref??", PACKAGE_NAME);
    
    
                holder.ck1.setChecked(sharedPrefs.getBoolean(PACKAGE_NAME,false));
                Log.d("just got boolean??", PACKAGE_NAME);
    
    
            }
    
            holder.ck1.setOnClickListener(new OnClickListener() {
    
                @Override
                public void onClick(View v) {
    
    
                    SharedPreferences.Editor editor = context.getSharedPreferences(packageInfo.packageName, Context.MODE_PRIVATE).edit();
    
                    if (holder.ck1.isChecked()) {
                        itemChecked[position] = true;
                        holder.ck1.setChecked(true);
                        Log.i("This is", " checked: " + position);
                        editor.putBoolean(packageInfo.packageName, true);
                        Log.d("put true", packageInfo.packageName);
    
                        editor.apply();
    
                    } else {
                        itemChecked[position] = false;
                        holder.ck1.setChecked(false);
                        Log.i("This is", " not checked: " + position);
                        editor.putBoolean(packageInfo.packageName, false);
                        Log.d("put false", packageInfo.packageName);
    
                        editor.apply();
    
                    }
    
                }
    
    
            });
    

    我为密钥传递了包名。 :)

    【讨论】:

      【解决方案2】:

      在您的情况下,我建议定义一个对象来处理存储和检索状态数据。假设您有一个 AppHandler 类作为您的主要对象和 AppState 类 用于保存与状态相关的数据,例如您的复选框。

      public class AppHandler {
      
          private List<AppState> lastInstalledApp;
          @transient
          private Gson            gson;
      
      
          public void retrieve(SharedPreferences pref){
      
              // parse the gson from shared preferences
              // create the lastInstalledApp list
              String jsonState = pref.getString("APP_STATE", null);
              if(jsonState != null)
                 lastInstalledApp = gson.fromJson(jsonState, lastInstalledApp.getClass());
          }
      
          public void store(SharedPreferences pref){
      
              // store the data to shared preferences
          }
      
      
          public List<AppState> getAppList(){
      
              return lastInstalledApp;
          }
      
          public static class AppState{
      
              protected boolean lastCheckbox;
              protected String name;
              public boolean isLastCheckbox() {
                  return lastCheckbox;
              }
              public void setLastCheckbox(boolean lastCheckbox) {
                  this.lastCheckbox = lastCheckbox;
              }
              public String getName() {
                  return name;
              }
              public void setName(String name) {
                  this.name = name;
              }
      
      
          }
      

      使用共享首选项将整个 AppHandler 对象存储为 JSON 字符串(为此使用 GSON),因此您只需访问存储文件一次,而不是每次您想要访问单个复选框状态时。您可以在您的活动中检索和存储此数据(适配器使用您的 appHandler.getAppList() 数据启动它):

      @Override
      protected void onCreate(Bundle arg0) {
          super.onCreate(arg0);
          setContentView(R.layout.list_layout);
      
          appHandler = new AppHandler();
          appHandler.retrieve(getSharedPreferences());
      }
      
      @Override
      protected void onDestroy() {
      
          appHandler.store(getSharedPreferences());
          super.onDestroy();
      }
      

      在您的自定义适配器中,通过其包名称访问特定应用程序,以获得复选框的状态。您甚至可以扩展 ArrayList 并添加一些方法,例如 getAppByName(),这样您就可以清楚地区分对象。
      更改复选框状态时,更新 AppState 对象的等效布尔值。这是笼统的说法。

      【讨论】:

      • 我阅读了您的回答,但我很困惑我将在哪里实施。我是否会使用与我在存储方法中的适配器中所做的类似的代码——创建一个 SharedPreference,将布尔值放入项目中?我想我会在检索方法中使用 getBoolean 方法?我无法理解从共享首选项解析 gson 的内容,创建 lastInstalledApp 列表。 GSON 会是最好的方法吗?因为我可能需要复选框的所有键值。感谢您的帮助,并对这些问题表示歉意。我想没有必要再解释一下了。
      • 感谢编辑!我想我现在有点明白了。但是解决上述问题确实会有所帮助xD
      • 您仅在 onCreate() 和 onDestroy() 上解析/存储 JSON,以便存储最后安装的应用程序。与他们的布尔值。根据应用程序包名称,您获得最后存储的布尔值并将其设置为相应的复选框。如果用户安装/卸载一个新应用程序,您可以将其添加到/从 lastInstalledApps 列表中删除。GSON 非常易于使用且有效。如果是最好的选择?很难说。但到目前为止对我来说效果很好。
      • 谢谢!! :) 最后安装的应用程序?还是您的意思是当前安装的应用程序?但我明白了。所以我想我必须更多地了解 JSON。有很多事情要做哈哈。嗯,我会像上面代码中那样使用 GSON 处于劣势吗?我知道主要区别在于 GSON 可以使用 Object 定义直接创建所需类型的对象。 JSONObject 需要手动解析。因此,假设我需要所有已检查应用程序的应用程序包名称,那么我可以使用 GSON 获得吗?还是我需要使用 JSON?
      • 我将其命名为最后安装,因为在存储时,它们会保存最后安装的应用程序的状态,因此当您的应用程序再次运行时,需要使用当前安装的应用程序更新列表。 GSON 是一个很好的谷歌图书馆。您可以使用纯 JSONObject,但为了简单起见,我更喜欢 GSON。相信我,您不需要学习很多关于 JSON/GSON 的知识。很简单
      【解决方案3】:

      使用 sqlite 数据库 ...每次用户选中/取消选中该值时,都会在数据库中创建一个条目。

      App1 已检查

      App2 已检查

      已检查 App3

      App4 未选中

      【讨论】:

      • 我的两门课是否走在正确的轨道上?问题是,如果用户下载任何其他应用程序,它可以抵消数据库
      • 感谢您的帮助,但我知道 SQLite 数据库是如何工作的,但我试图找出具体实现以防我的特殊情况。
      • @XiJiaopin 对不起,我不明白这个问题......你只需要为每个应用程序保留一个标志......当用户添加一个新应用程序时,默认标志是未选中的
      • 这就是我想弄清楚如何为啊哈编写代码
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-11-05
      • 2014-03-31
      • 2018-02-06
      • 2018-12-18
      • 2017-04-28
      • 1970-01-01
      • 2019-01-23
      相关资源
      最近更新 更多