0

Three fragments in my app, Fragment1, Fragment2, Fragment3 display contents of a single table in a listview, using a single custom CursorAdapter class, TaskCursorAdapter. Here is the class:

public class TaskCursorAdapter extends CursorAdapter {
    public TaskCursorAdapter(Context context, Cursor c) {
        super(context, c, 0 /* flags */);
    }
    @Override
    public View newView(Context context, Cursor cursor, ViewGroup parent) {
        return LayoutInflater.from(context).inflate(R.layout.list_item_task, parent, false);
    }
    @Override
    public void bindView(View view, Context context, Cursor cursor) {
        TextView titleTextView = (TextView) view.findViewById(R.id.task_title);
        TextView detailsTextView = (TextView) view.findViewById(R.id.task_details);
        int titleColumnIndex = cursor.getColumnIndex(TaskEntry.COLUMN_TASK_TITLE);
        int detailsColumnIndex = cursor.getColumnIndex(TaskEntry.COLUMN_TASK_DETAILS);
        String taskTitle = cursor.getString(titleColumnIndex);
        String taskDetails = cursor.getString(detailsColumnIndex);
        if (TextUtils.isEmpty(taskDetails)) {
            taskDetails = context.getString(R.string.unknown_task);
        }
        titleTextView.setText(taskTitle);
        detailsTextView.setText(taskDetails);
    }
}

The table is specified in the Contract class as TaskEntry. It also has another column named TaskEntry.COLUMN_TASK_STATUS="status". The possible values are 0, 1 or 2. Currently, all the items are displayed in both fragments. But, I want to make it so that only the rows with status=0 are displayed in Fragment1, those with status=1 in Fragment2 and those with status=2 in Fragment3.

I tried the following in bindView method:

int taskStatus = Integer.parseInt(cursor.getString(cursor.getColumnIndex(TaskEntry.COLUMN_TASK_STATUS)));
if(taskStatus==0) { //code in bindView }

This resulted in displaying only the items with status=0 in all fragments, but it left an empty inflated view in place of the item with status other than 0. Also, I cannot find a way to pass the information to make it specific to Fragment1.

How should I conditionally display rows based on status value and fragment?

EDIT: What worked:

Instead of trying this in TaskCursorAdapter, I used conditional query in onCreateLoader method like the following in each fragment:

public Loader<Cursor> onCreateLoader(int id, Bundle args) {
    String selectionArgs[] = {"<status>"};
    String[] projection = {
            TaskEntry._ID,
            TaskEntry.COLUMN_TASK_TITLE,
            TaskEntry.COLUMN_TASK_DETAILS};
    return new CursorLoader(this.getActivity(), TaskEntry.CONTENT_URI, projection,
            TaskEntry.COLUMN_TASK_STATUS + " = ?", selectionArgs, null);
}

1 Answers1

-1

Try this:

public class TaskCursorAdapter extends CursorAdapter {
    private int statusCode;        

    public TaskCursorAdapter(Context context, Cursor c) {
        super(context, c, 0 /* flags */);
    }

    public setStatusCode(int statusCode){
        this.statusCode = statusCode;
    }

    @Override
    public View newView(Context context, Cursor cursor, ViewGroup parent) {
        int currentStatusCode = Integer.parseInt(cursor.getString(cursor.getColumnIndex(TaskEntry.COLUMN_TASK_STATUS)));
        if(statusCode == currentStatusCode){
            return LayoutInflater.from(context).inflate(R.layout.list_item_task, parent, false);
         } else return null;
    }

    @Override
    public void bindView(View view, Context context, Cursor cursor) {
        if(view != null){
            TextView titleTextView = (TextView) view.findViewById(R.id.task_title);
            TextView detailsTextView = (TextView) view.findViewById(R.id.task_details);
            int titleColumnIndex = cursor.getColumnIndex(TaskEntry.COLUMN_TASK_TITLE);
            int detailsColumnIndex = cursor.getColumnIndex(TaskEntry.COLUMN_TASK_DETAILS);
            String taskTitle = cursor.getString(titleColumnIndex);
            String taskDetails = cursor.getString(detailsColumnIndex);
            if (TextUtils.isEmpty(taskDetails)) {
                taskDetails = context.getString(R.string.unknown_task);
            }
            titleTextView.setText(taskTitle);
            detailsTextView.setText(taskDetails);
        }
    }
}

and do this in each of your fragments, passing in your status codes, respectively:

 yourAdapter = new TaskCursorAdapter(this, yourDataCursor);
 yourAdapter.setStatusCode(YOUR_STATUS_CODE);
 yourListView.setAdapter(yourAdapter);

EDIT (It turns out we can't return null from CursorAdapter#newView()

So I guess you are going to have to filter your cursor in each Fragment before instantiating a new TaskCursorAdapter, and pass in your filtered cursor instead of your original cursor. You can use CursorWrapper class for that. This answer might give you an idea: https://stackoverflow.com/a/7343721/8354184.

Onur D.
  • 344
  • 2
  • 11
  • I tried this, and this resulted in the termination of the app as soon as it launched, with the following exception: java.lang.NullPointerException: Attempt to invoke virtual method 'int android.view.View.getImportantForAccessibility()' on a null object reference – Apurva Bhargava Oct 06 '18 at 19:54
  • It would seem that adding condition (view!=null) did not help the case of returning null from newView method. But testing for statusCode in bindView would result in unnecessary views being inflated. – Apurva Bhargava Oct 06 '18 at 20:02
  • I see. So I think you should use different cursors for each of your fragments. To do that, instead of querying the database each time, I'd suggest implementing a CursorWrapper with your logic of filtering results -according to their status codes- and use it instead of your original cursor. – Onur D. Oct 06 '18 at 20:31
  • Alright, I was hesitant about using different cursors, wondering if it was inefficient or bad practice in general. Thank you, I'll go with your suggestion of using different cursors, if no work around exists. – Apurva Bhargava Oct 06 '18 at 21:05
  • Just make sure that you don't query the database each time, since that would be really expensive. Instead, get your cursor once and then use CursorWrapper to filter your rows. You might need to write your own custom CursorWrapper to have the functionality you want :) – Onur D. Oct 06 '18 at 21:12