0

I'm trying to populate a listview with a sqlite database, so far I think I've properly created/added items to the database. I'm not sure how to get those items and put them in my list view.

Here is my database creation(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;

}

This is where I add buttons on button click(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();

Here is where I have my listview that I want to populate using the sqlite db and my 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);

And heres my 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"/>

And here is my CursorAdapter so far:

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

I'm not sure how I would go about getting the listview to populate using the sqlite db.. I think I am adding items to the db the correct way though. Thanks for any help!

2
  • Your adapter looks correct. You just need to create an instance of TodoCursorAdapter and send it to setAdapter() on your ListView. You might also consider using SimpleCursorAdapter since it does everything that you are doing in TodoCursorAdapter. Commented Aug 12, 2016 at 18:54
  • Would you be able to give an example please, when I try to create instance of TodoCursorAdapter in MyProgress.java, Im not sure what to put for the expected parameters "cursor" and "flags" Commented Aug 12, 2016 at 19:07

2 Answers 2

1

First I suggest a change to the TodoCursorAdapter constructor:

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

I'm confused by the flags parameter myself. Especially since the Cursor constructor which takes no flags has been deprecated for some time now. From what I can tell, a value of 0 here will work fine.

Next, you need to remove the RecordsDatabase rdb parameter from both putInformation() and getRecords(). This parameter is completely unnecessary because Java already sends it automatically as the keyword this. However, you don't actually need to use this anywhere. You simply call any method you wish to use directly. So instead of

rdb.getWritableDatabase();

just do

getWritableDatabase();

Alternatively, you can do

this.getWritableDatabase();

but this is automatically assumed if you leave it off.

Now you need a Cursor in order to pass to the TodoCursorAdapter constructor. You do this using your RecordsDatabase which extends SQLiteOpenHelper:

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

Also, you might consider removing the Cursor parameter from the TodoCursorAdapter constructor. The other options are

  1. Create the Cursor directly in the TodoCursorAdapter constructor
  2. Create the Cursor in MyProgress and call changeCursor() on the adapter.
Sign up to request clarification or add additional context in comments.

5 Comments

Thanks, I got this to run with no errors, but when I click the "MyProgress" page, it crashes and I get: java.lang.IllegalArgumentException: column '_id' does not exist.. not sure where it is trying to check for that lol
It sends me to the ToDoCursorAdapter class, and the MyProgress class, This line in my progress: TodoCursorAdapter adapter = new TodoCursorAdapter(this, c);
@LBJ33 Some Android API methods expect any SQLite table to have a column named _id. The easiest solution is to just add this to your table. Alternatively, you can determine which methods require this and avoid using them. This seems to take too much work IMO...and it means writing more code since you won't be able to rely on the API to do the work for you.
I changed my create table to include: db.execSQL("CREATE TABLE " + RecordContract.RecordInfo.TABLE_NAME + " (" + BaseColumns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," + RecordContract.RecordInfo.RECORDS_DATE + " TEXT NOT NULL," Still get same error, am I missing something?
You need to uninstall your app before trying these changes. The new CREATE TABLE query is not called because the database already exists and so onCreate() is not called in your SQLiteOpenHelper subclass.
1

You need to make an object of adapter and set it as the adapter of the ListView.

In your activity after this line.

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

Put this code.

First get all records from the RecordsDatabase class

Cursor recordsCursor = recordsDatabase.getRecords();

Then make an object of TodoCursorAdapter.

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

According to developer.android.com About FLAG_REGISTER_CONTENT_OBSERVER

If set the adapter will register a content observer on the cursor and will call onContentChanged() when a notification comes in. Be careful when using this flag: you will need to unset the current Cursor from the adapter to avoid leaks due to its registered observers. This flag is not needed when using a CursorAdapter with a CursorLoader.

Then set this adapter as adapter of ListView.

listViewRec.setAdapter(adapter);

6 Comments

It would be better to keep RecordsAdapter extends CursorAdapter rather than change it to RecordsAdapter extends ArrayAdapter. That way the adapter will automatically update the ListView when the underlying database changes rather than requiring code to query the database and update the ListView manually. Also, a Cursor does not keep all records in memory as a ListView does.
Was just submitting the updated answer while you voted down. Please have a look now and adjust the vote if answer is good now
That is better...assuming getRecords() is changed to take no parameters (as it should). On another typic (since you brought it up here)...I'm confused about FLAG_REGISTER_CONTENT_OBSERVER. Do you know what a "content observer" does? The documentation for onContentChanged() hints that it is related to the requery mechanism for the outdated managed queries. If that is so, this flag shouldn't be used. I assume that means that we should just use a flag value of 0, but I have not yet confirmed if this is correct.
I think its some kind of watch on the collection or data on which it is registered. And yes onContentChanged() depicts a requery mechanism. But there is nothing mentioned in the document regarding using 0 when you don't wanna used that flag. It might crash the app somehow maybe. What do u say ?
"there is nothing mentioned in the document regarding using 0 when you don't wanna used that flag" That's exactly why I'm confused. As far as I can tell, both flag values which are documented are related to managed cursors which are deprecated. The documentation says that we should use CursorLoaders instead but doesn't specify what flag value to use. My educated guess is that 0 means no flags are set and so seems like a reasonable value to use.
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.