【问题标题】:Populating listview with sqlite db使用 sqlite db 填充列表视图
【发布时间】:2016-08-12 18:42:04
【问题描述】:

我正在尝试使用 sqlite 数据库填充列表视图,到目前为止,我认为我已经正确地创建/添加了项目到数据库中。我不确定如何获取这些项目并将它们放在我的列表视图中。

这是我的数据库创建(RecordsDatabase.java):

public class RecordsDatabase extends SQLiteOpenHelper {

public static final int DATABASE_VERSION = 1;

public RecordsDatabase(Context context) {
    super(context, RecordContract.RecordInfo.DATABASE_NAME, null, DATABASE_VERSION);
    Log.d("Database operations", "Database created");
}

@Override
public void onCreate(SQLiteDatabase db) {
    db.execSQL("CREATE TABLE " + RecordContract.RecordInfo.TABLE_NAME + " ("
                    + RecordContract.RecordInfo.RECORDS_DATE + " TEXT NOT NULL,"
            + RecordContract.RecordInfo.RECORDS_SQUAT + " TEXT NOT NULL,"
            + RecordContract.RecordInfo.RECORDS_BENCH + " TEXT NOT NULL,"
            + RecordContract.RecordInfo.RECORDS_DEAD + " TEXT NOT NULL,"
            + RecordContract.RecordInfo.RECORDS_TOTAL + " TEXT NOT NULL)"

    );
    Log.d("Database operations", "Table created");

}

@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

}

public void putInformation(RecordsDatabase rdb, String date, String squat, String bench, String dead, String total) {
    SQLiteDatabase SQ = rdb.getWritableDatabase();
    ContentValues contentValues = new ContentValues();
    contentValues.put(RecordContract.RecordInfo.RECORDS_DATE, date);
    contentValues.put(RecordContract.RecordInfo.RECORDS_SQUAT, squat);
    contentValues.put(RecordContract.RecordInfo.RECORDS_BENCH, bench);
    contentValues.put(RecordContract.RecordInfo.RECORDS_DEAD, dead);
    contentValues.put(RecordContract.RecordInfo.RECORDS_TOTAL, total);
    long k = SQ.insert(RecordContract.RecordInfo.TABLE_NAME, null, contentValues);
    Log.d("Database operations", "Record added(1 row)");

}

public Cursor getRecords(RecordsDatabase rdb) {
    SQLiteDatabase SQ = rdb.getReadableDatabase();
    String[] columns = {RecordContract.RecordInfo.RECORDS_DATE, RecordContract.RecordInfo.RECORDS_SQUAT, RecordContract.RecordInfo.RECORDS_BENCH
    , RecordContract.RecordInfo.RECORDS_DEAD, RecordContract.RecordInfo.RECORDS_TOTAL};
    Cursor CR = SQ.query(RecordContract.RecordInfo.TABLE_NAME, columns,null, null, null, null, null);
    return CR;

}

这是我在按钮单击(MyMaxes.java)上添加按钮的地方:

 mButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            SharedPreferences pref = getApplicationContext().getSharedPreferences("MyPref", 0);
            SharedPreferences.Editor editor = pref.edit();
                if (mEditTextBench.getText().length() > 0 && mEditTextDead.getText().length() > 0 && mEditTextSquat.getText().length() > 0) {
                maxBenchDB = mEditTextBench.getText().toString();
                maxSquatDB = mEditTextSquat.getText().toString();
                maxDeadDB = mEditTextDead.getText().toString();
                maxTotalDB = mTxtTotal.getText().toString();

                DateFormat df = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss");
                Date today = Calendar.getInstance().getTime();
                reportDate = df.format(today);

                RecordsDatabase DB = new RecordsDatabase(mContext);
                DB.putInformation(DB, reportDate, maxSquatDB, maxDeadDB, maxBenchDB, maxTotalDB);
                Toast.makeText(getBaseContext(), "added", Toast.LENGTH_LONG).show();

这是我想要使用 sqlite db 和我的 custom.xml(MyProgress.java) 填充的列表视图:

public class MyProgress extends BaseActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.my_progress);
    mToolBar = activateToolbar();
    setUpNavigationDrawer();
    getSupportActionBar().setTitle("My Progress");

    ListView listViewRec = (ListView) findViewById(R.id.listViewRecord);

这是我的 custom_record.xml:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
          android:orientation="vertical"
          android:layout_width="match_parent"
          android:layout_height="match_parent">

<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Date"
    android:textSize="18sp"
    android:id="@+id/txtDate"
    android:layout_alignParentTop="true"
    android:layout_alignParentLeft="true"
    android:layout_alignParentStart="true"/>

<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Bench"
    android:id="@+id/txtBench"
    android:paddingRight="5dp"
    android:textSize="18sp"
    android:layout_gravity="center_horizontal"
    android:layout_alignParentTop="true"
    android:paddingLeft="5dp"
    android:layout_toLeftOf="@+id/txtSquat"
    android:layout_toStartOf="@+id/txtSquat"/>

<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Squat"
    android:textSize="18sp"
    android:paddingRight="5dp"
    android:id="@+id/txtSquat"
    android:layout_alignParentTop="true"
    android:paddingLeft="5dp"
    android:layout_toLeftOf="@+id/txtDead"
    android:layout_toStartOf="@+id/txtDead"
    />

<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Dead"
    android:paddingRight="5dp"
    android:textSize="18sp"
    android:id="@+id/txtDead"
    android:layout_alignParentTop="true"
    android:paddingLeft="5dp"
    android:layout_toLeftOf="@+id/txtTotal"
    android:layout_toStartOf="@+id/txtTotal"/>

<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Total"
    android:textSize="18sp"
    android:paddingRight="5dp"
    android:paddingLeft="5dp"
    android:id="@+id/txtTotal"
    android:layout_marginRight="34dp"
    android:layout_marginEnd="34dp"

    android:layout_alignParentRight="true"
    android:layout_alignParentEnd="true"/>

到目前为止,这是我的 CursorAdapter:

public class TodoCursorAdapter extends CursorAdapter {

  public TodoCursorAdapter(Context context, Cursor c, int flags) {
          super(context, c, flags);
  }

  @Override
  public View newView(Context context, Cursor cursor, ViewGroup parent) {
          return LayoutInflater.from(context).inflate(R.layout.custom_record, parent, false);
  }

  @Override
  public void bindView(View view, Context context, Cursor cursor) {
          TextView txtDate = (TextView) view.findViewById(R.id.txtDate);
          TextView txtSquat = (TextView) view.findViewById(R.id.txtSquat);
          TextView txtBench = (TextView) view.findViewById(R.id.txtBench);
          TextView txtDead = (TextView) view.findViewById(R.id.txtDead);
          TextView txtTotal = (TextView) view.findViewById(R.id.txtTotal);

          String date = cursor.getString(cursor.getColumnIndexOrThrow("date"));
          String squat = cursor.getString(cursor.getColumnIndexOrThrow("squat"));
          String bench = cursor.getString(cursor.getColumnIndexOrThrow("bench"));
          String dead = cursor.getString(cursor.getColumnIndexOrThrow("dead"));
          String total = cursor.getString(cursor.getColumnIndexOrThrow("total"));

          txtBench.setText(bench);
          txtDate.setText(date);
          txtDead.setText(dead);
          txtSquat.setText(squat);
          txtTotal.setText(total);
  }
}

我不确定如何使用 sqlite db 来填充 listview。我认为我正在以正确的方式将项目添加到 db。感谢您的帮助!

【问题讨论】:

  • 您的适配器看起来正确。您只需要创建一个TodoCursorAdapter 的实例并将其发送到您的ListView 上的setAdapter()。您也可以考虑使用SimpleCursorAdapter,因为它可以完成您在TodoCursorAdapter 中所做的一切。
  • 你能举个例子吗,当我尝试在 MyProgress.java 中创建 TodoCursorAdapter 的实例时,我不确定要为预期的参数“光标”和“标志”放什么跨度>

标签: android sqlite listview android-sqlite android-cursoradapter


【解决方案1】:

首先我建议更改TodoCursorAdapter 构造函数:

public TodoCursorAdapter(Context context, Cursor c) {
    super(context, c, 0);
}

我自己对 flags 参数感到困惑。尤其是因为 Cursor 不带标志的构造函数已经被弃用了一段时间。据我所知,0 这里的值可以正常工作。

接下来,您需要从putInformation()getRecords() 中删除RecordsDatabase rdb 参数。这个参数是完全没有必要的,因为 Java 已经将它作为关键字 this 自动发送。但是,您实际上不需要在任何地方使用this。您只需直接调用您希望使用的任何方法。所以不是

rdb.getWritableDatabase();

只是做

getWritableDatabase();

或者,你可以这样做

this.getWritableDatabase();

但如果您不使用this,则会自动假定为this

现在你需要一个Cursor 来传递给TodoCursorAdapter 构造函数。您可以使用扩展 SQLiteOpenHelperRecordsDatabase 来执行此操作:

public class MyProgress {
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        // ...snip
        RecordsDatabase helper = new RecordsDatabase(this);
        Cursor c = db.getRecords();
        ListView listViewRec = (ListView) findViewById(R.id.listViewRecord);
        Adapter adapter = new TodoRecordsAdapter(this, c);
        listViewRec.setAdapter(adapter);
    }
}

另外,您可以考虑从TodoCursorAdapter 构造函数中删除Cursor 参数。其他选项是

  1. 直接在TodoCursorAdapter构造函数中创建Cursor
  2. MyProgress 中创建Cursor 并在适配器上调用changeCursor()

【讨论】:

  • 谢谢,我让它运行没有错误,但是当我点击“MyProgress”页面时,它崩溃了,我得到:java.lang.IllegalArgumentException: column '_id' does not exist..不知道它在哪里尝试检查那个大声笑
  • 它将我发送到 ToDoCursorAdapter 类和 MyProgress 类,我的进度中的这一行:TodoCursorAdapter adapter = new TodoCursorAdapter(this, c);
  • @LBJ33 一些 Android API 方法要求任何 SQLite 表都有一个名为 _id 的列。最简单的解决方案是将其添加到您的表中。或者,您可以确定哪些方法需要这样做并避免使用它们。 IMO 似乎需要做太多工作......这意味着编写更多代码,因为您将无法依赖 API 为您完成工作。
  • 我将创建表更改为包括: db.execSQL("CREATE TABLE " + RecordContract.RecordInfo.TABLE_NAME + " (" + BaseColumns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," + RecordContract.RecordInfo .RECORDS_DATE + " TEXT NOT NULL," 仍然出现同样的错误,我错过了什么吗?
  • 您需要先卸载您的应用,然后再尝试这些更改。未调用新的 CREATE TABLE 查询,因为数据库已存在,因此在您的 SQLiteOpenHelper 子类中未调用 onCreate()
【解决方案2】:

你需要制作一个adapter的对象,并将其设置为ListView的adapter。

在此行之后的活动中。

ListView listViewRec = (ListView) findViewById(R.id.listViewRecord);

输入这段代码。

首先从 RecordsDatabase 类中获取所有记录

Cursor recordsCursor = recordsDatabase.getRecords();

然后制作一个 TodoCursorAdapter 的对象。

TodoCursorAdapter adapter = new TodoCursorAdapter(getContext(), recordsCursor, 
CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);

根据 developer.android.com 关于 FLAG_REGISTER_CONTENT_OBSERVER

如果设置,适配器将在光标上注册一个内容观察器,并在收到通知时调用 onContentChanged()。使用此标志时要小心:您需要从适配器取消设置当前光标以避免由于以下原因导致的泄漏其注册观察员。将 CursorAdapter 与 CursorLoader 一起使用时不需要此标志。

然后将此适配器设置为ListView的适配器。

listViewRec.setAdapter(adapter);

【讨论】:

  • 最好保留RecordsAdapter extends CursorAdapter,而不是改为RecordsAdapter extends ArrayAdapter。这样,当底层数据库发生变化时,适配器将自动更新ListView,而不是需要代码来查询数据库并手动更新ListView。此外,Cursor 不会像 ListView 那样将所有记录保存在内存中。
  • 在您投反对票时刚刚提交了更新的答案。如果现在回答好,请立即查看并调整投票
  • 这样更好...假设 getRecords() 更改为不带参数(应该如此)。在另一个典型上(因为您在这里提出了它)...我对FLAG_REGISTER_CONTENT_OBSERVER 感到困惑。你知道“内容观察者”是做什么的吗? onContentChanged() 的文档暗示它与过时的托管查询的重新查询机制有关。如果是这样,则不应使用此标志。我认为这意味着我们应该只使用0 的标志值,但我尚未确认这是否正确。
  • 我认为它是对它所注册的集合或数据的某种监视。是的 onContentChanged() 描述了一个重新查询机制。但是文档中没有提到当您不想使用该标志时使用 0 。它可能会以某种方式使应用程序崩溃。你说什么?
  • “文档中没有提到当您不想使用该标志时使用 0”这正是我感到困惑的原因。据我所知,记录的两个标志值都与已弃用的托管游标有关。文档说我们应该改用CursorLoaders,但没有指定要使用的标志值。我有根据的猜测是0 表示没有设置任何标志,因此使用起来似乎是一个合理的值。
猜你喜欢
  • 2011-02-28
  • 1970-01-01
  • 1970-01-01
  • 2017-08-10
  • 1970-01-01
  • 2018-02-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多