4

Each item of my SherlockListFragment contains 3 TextViews : a name and two numbers. The data comes from the table objective of my database, which has the following structure :

CREATE TABLE objective (
    _id INTEGER PRIMARY KEY,
    id_project INTEGER NOT NULL,
    activity_code INTEGER NOT NULL,
    day_duration INTEGER NOT NULL,
    week_frequency INTEGER NOT NULL,
    FOREIGN KEY(id_project) REFERENCES project(id_project)
);

Moreover, I have read that populating a list from a cursor should be done by using a loader (particularly when using a database because it can be a very slow operation). I have found a SimpleCursorLoader class here on stackoverflow, but it maps data to a field directly.

That is not really what I want, because as you can see, in my objective table I have an activity_code. So I would like to replace it by a string (I have an Enum that lists all of my activity codes and returns, for each one, a string resource identifier).

Do you know how I could manipulate data before it is displayed in the TextViews ?

Here is my SherlockListFragment

public class ObjectivesDisplayFragment extends SherlockListFragment implements LoaderManager.LoaderCallbacks<Cursor>
{
    private Activity activity;
    private SimpleCursorAdapter adapter;


    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) 
    {
        return inflater.inflate(R.layout.objectives_display, container, false);
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState)
    {
        super.onActivityCreated(savedInstanceState);
        activity = getActivity();

        String[] columns = new String[] { "activity_code", "day_duration", "week_frequency" };
        int[] to = new int[] { R.id.activityName, R.id.objectiveDuration, R.id.objectiveFrequency };

        getLoaderManager().initLoader(0x01, null, this);

        adapter = new SimpleCursorAdapter(activity.getApplicationContext(), R.layout.objective_row, null, columns, to, SimpleCursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);
        setListAdapter(adapter);
    }

    public Loader<Cursor> onCreateLoader(int arg0, Bundle arg1) {
        return new SimpleCursorLoader(activity) {
            @Override
            public Cursor loadInBackground() {
                DatabaseHelper dbHelper = DatabaseHelper.getInstance(activity);

                String query = "SELECT _id, activity_code, day_duration, week_frequency FROM objective WHERE id_project = ?";
                String[] args = new String[] { "1" }; // projectId
                Cursor results = dbHelper.getReadableDatabase().rawQuery(query, args);

                return results;
            }
        };
    }

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

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

EDIT : I do not need to close the cursor and the database in SimpleCursorLoader > loadInBackground, right ? Otherwise the data could not be read. So is the closing operation automatically handled or do I need to do it myself elsewhere?

Community
  • 1
  • 1
Romain Guidoux
  • 2,943
  • 4
  • 28
  • 48

1 Answers1

3

I guess this may work for you:

adapter.setViewBinder(new ViewBinder(){
        @Override
        public boolean setViewValue(View view, Cursor cursor, int columnIndex) {
            String label = "Inactive";

            if(columnIndex == 4) {
                if(cursor.getInt(columnIndex) == 1) {
                    label = "Active";
                }

                TextView tv = (TextView) view.findViewById(R.id.status);
                tv.setText(label);

                return true;
            }

            return false;
        }
    });

    setListAdapter(adapter);

Background information: I had a foreign key column (integer) in the table and wanted to resolve to it's string value (from linked table) upon populating in the list view. Column was at 4th index (5th column in set), so just used setViewBinder() to manipulate the required column.

Further my layout had 5 text views to display the 5 fields from cursor. One thing also NOTICEABLE here is, when using "if" conditions to catch your column indexes, make sure every conditional block must contain "return true". In such case where interpreter reaches "return false" - means your field didn't get manipulated.

I am sure the above code block is pretty much simple and easy to understand.

Waqas Hasan
  • 98
  • 1
  • 9
  • 1
    As a note, you can replace TextView tv = (TextView) view.findViewById(R.id.status); with TextView tv = (TextView) view; – Waqas Hasan Aug 31 '12 at 18:41
  • Many thanks, it works wonderfully ! Do you know if I have to close the cursor and/or the database somewhere ? Or is it handled automatically ? – Romain Guidoux Aug 31 '12 at 19:24
  • if you are using DatabaseHelper appropriately, and opening closing the database using standard methods, then I think there's no need. However, as a shared thought, I am using it the standard way, i.e.: connection to database opens at time of onCreate of Activity, it is closed at onPause and later re-opened at onResume. Another thought (not so sure, means didn't apply yet), if you close the cursor at the end of the operation, you might not be able to reload the list upon changes, you might need to reopen the cursor, so I guess, don't bother to open/close cursor in this case. (I am a newbie) – Waqas Hasan Aug 31 '12 at 20:06