Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Filtering ListView by 'selection' parameter in CursorLoader

I either have my syntax incorrect or I haven't understood how Loaders work yet, but I've currently got a ListView showing all items in my database. The activity has a button with today's date showing. The user can click this to bring up a Date Dialog or can press the Prev/Next buttons to change the date displayed. I'd like to filter the ListView based on the date showing, so only records with that date saved in will display.

Currently all records are showing with

public Loader<Cursor> onCreateLoader(int id, Bundle args) {         
    CursorLoader cl = new CursorLoader(this, DBProvider.CONTENT_URI,
            null, null, null, null);
    return cl;
}

I've tried a few variations based on what I'm seeing online but essentially I'm trying to include a 'selection' that shows today's date as a string (it's already been through SimpleDateFormatter and set as the text on the button).

public Loader<Cursor> onCreateLoader(int id, Bundle args) { 
    String[] selectDate = { btn_logbook_date.getText().toString() };
    CursorLoader cl = new CursorLoader(this, DBProvider.CONTENT_URI,
            null, "Date=?", selectDate , null);
    return cl;
}

and

public Loader<Cursor> onCreateLoader(int id, Bundle args) { 
    String selectDate = btn_logbook_date.getText().toString();
    String selection = "(" + AddDBHelper.KEY_DATE + "=" + selectDate + ")";

    CursorLoader cl = new CursorLoader(this, DBProvider.CONTENT_URI,
            null, selection, null, null);
    return cl;
}

both generate NullPointerExceptions. Any pointers on the correct method to filter this on creating the loader would be appreciated.

UPDATE

It seems the NullPointerException was occurring because I was calling the fillData() method (used to populate my ListView) before calling my btn_logbook_date.setText() method. I've moved this further down in my activity's onCreate and the application no longer crashes, but the data is not populating anymore. I realised that if I save a new record in with today's date, it shows up in my listview, but when changing days no other records are appearing. Changing back to today in the ListView activity also shows up blank.

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView (R.layout.dash_logbook);     
    this.getListView().setDividerHeight(2);         

    ListView list = getListView();
    list.setOnItemClickListener(this);

    btn_logbook_date = (Button) findViewById(R.id.btn_logbook_date);
    now = Calendar.getInstance();
    nowD = now.getTime();

    SimpleDateFormat dFormatter = new SimpleDateFormat("dd MMM yyyy");
    strDate = dFormatter.format(nowD);
    btn_logbook_date.setText(strDate);              

    fillData();
}

// I have code here to call on the DateDialogFragment

public void updateDatePrev() {
    String prevVar[] = btn_logbook_date.getText().toString().split(" ");

    if (prevVar[1].equalsIgnoreCase("Jan")) {
        lMonth = 0;
    } else if (prevVar[1].equalsIgnoreCase("Feb")) {
        lMonth = 1;
    } else if (prevVar[1].equalsIgnoreCase("Mar")) {
        lMonth = 2;
    } else if (prevVar[1].equalsIgnoreCase("Apr")) {
        lMonth = 3;
    } else if (prevVar[1].equalsIgnoreCase("May")) {
        lMonth = 4;
    } else if (prevVar[1].equalsIgnoreCase("Jun")) {
        lMonth = 5;
    } else if (prevVar[1].equalsIgnoreCase("Jul")) {
        lMonth = 6;
    } else if (prevVar[1].equalsIgnoreCase("Aug")) {
        lMonth = 7;
    } else if (prevVar[1].equalsIgnoreCase("Sep")) {
        lMonth = 8;
    } else if (prevVar[1].equalsIgnoreCase("Oct")) {
        lMonth = 9;
    } else if (prevVar[1].equalsIgnoreCase("Nov")) {
        lMonth = 10;
    } else if (prevVar[1].equalsIgnoreCase("Dec")) {
        lMonth = 11;
    }

    int lYear = Integer.parseInt(prevVar[2]);
    int lDay = Integer.parseInt(prevVar[0]);
    now = Calendar.getInstance();
    now.set(Calendar.YEAR, lYear);
    now.set(Calendar.MONTH, lMonth);
    now.set(Calendar.DAY_OF_MONTH, lDay - 1);
    PrevDate = now.getTime();
    SimpleDateFormat prevDFormatter = new SimpleDateFormat("dd MMM yyyy");
    strDate = prevDFormatter.format(PrevDate);
    btn_logbook_date.setText(strDate);      
}

public void updateDateNext() {
//same code as above, except adding +1 to the days when clicked
}

private void fillData() {
    // Fields from the database (projection) must include
    // the _id column for the adapter to work
    String[] from = new String[] { AddDBHelper.KEY_BGL, AddDBHelper.KEY_ROWID,
            AddDBHelper.KEY_CATEG, AddDBHelper.KEY_TIME };
    // Fields on the UI to which we map
    int[] to = new int[] {R.id.logBGL, R.id.logRowID, R.id.logCateg, R.id.logTime };

    getLoaderManager().initLoader(0, null, this);
    adapter = new SimpleCursorAdapter(this, R.layout.logbook_item, null, from, to, 0);

    setListAdapter(adapter);        
}    

public Loader<Cursor> onCreateLoader(int id, Bundle args) { 
     String selection = AddDBHelper.KEY_DATE + "=?";
     String[] selectionArgs = { String.valueOf(btn_logbook_date.getText().toString()) };

    CursorLoader cl = new CursorLoader(this, DBProvider.CONTENT_URI,
            null, selection, selectionArgs, null);
    return cl;
}

public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
    adapter.swapCursor(data);
}

public void onLoaderReset(Loader<Cursor> loader) {
    adapter.swapCursor(null);
}

When originally saving to the database from a different activity, I'm also using the SimpleDateFormat method and converting to the same format as above, so the saved strings and the Text being displayed on the button should match.

UPDATE

I've answered this question below. The issue about repopulating the list will be asked separately as the original question was only regarding filtering the list by date. I confirmed this was working by creating new records with today's date and having them populate when opening the listview activity. By changing the date in the Android emulator and then re-opening the application and listview activity, i could see the records belonging to the newly set date.

like image 718
Ronnie Avatar asked Nov 03 '22 13:11

Ronnie


2 Answers

Either btn_logbook_date or btn_logbook_date.getText() is null.

like image 118
CL. Avatar answered Nov 08 '22 10:11

CL.


As shown above, my fillData() method was being called in my activity's onCreate, but I was incorrectly calling it BEFORE setting the date on my button. The fillData() is used to populate the list and initialise my loader. The loader was filtering based on the date displayed on my button. By setting the date on the button AFTER attempting to call fillData(), the list had no value to get from the button resulting in a NullPointerException.

The correct code is shown again below for clarification purposes.

protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView (R.layout.dash_logbook);     
this.getListView().setDividerHeight(2);         

ListView list = getListView();
list.setOnItemClickListener(this);

btn_logbook_date = (Button) findViewById(R.id.btn_logbook_date);
now = Calendar.getInstance();
nowD = now.getTime();

SimpleDateFormat dFormatter = new SimpleDateFormat("dd MMM yyyy");
strDate = dFormatter.format(nowD);
// Set the text on this button BEFORE calling the fillData() method
btn_logbook_date.setText(strDate);              

fillData();
}

private void fillData() {       
    String[] from = new String[] { AddDBHelper.KEY_BGL, AddDBHelper.KEY_ROWID,
            AddDBHelper.KEY_CATEG, AddDBHelper.KEY_TIME };
    int[] to = new int[] {R.id.logBGL, R.id.logRowID, R.id.logCateg, R.id.logTime };

    getLoaderManager().initLoader(0, null, this);
    adapter = new SimpleCursorAdapter(this, R.layout.logbook_item, null, from, to, 0);

    setListAdapter(adapter);
}

public Loader<Cursor> onCreateLoader(int id, Bundle args) { 
     String selection = AddDBHelper.KEY_DATE + "=?";
     String[] selectionArgs = { String.valueOf(btn_logbook_date.getText().toString()) };

    CursorLoader cl = new CursorLoader(this, DBProvider.CONTENT_URI,
            null, selection, selectionArgs, null);
    return cl;
}

public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
    adapter.swapCursor(data);
}

public void onLoaderReset(Loader<Cursor> loader) {
    // data is not available anymore; delete reference
    adapter.swapCursor(null);
}
like image 43
Ronnie Avatar answered Nov 08 '22 09:11

Ronnie