views:

359

answers:

1

I have an app using a ListView as a main screen. Each row displays some text, a checkbox and images according to the data, and since you can't do that with a standard ListAdapter, I crafted my own.

Every time a change occur (adding / removing a row, checking a tip, navigating, etc) to the list data, I refresh the list display, using this method :

public void refreshList()
{
    // fetch the new items
    ItemDbHelper items = new ItemDbHelper(this);
    Cursor item_cursor = items.fetchItemForCurrentView(this.current_context_filter);

    // do not use "start managing cursor" here or resume() won't work
    // anymore since the cursor will be closed despite we still need it

    // set the welcome message if no items to display
    if (item_cursor.getCount() == 0)
    {
        TextView message = (TextView) this.findViewById(R.id.home_message);
        message.setVisibility(View.VISIBLE);
    }

    ListView list = this.task_list;
    ItemListAdapter item_cursor_adater = (ItemListAdapter) list.getAdapter();

    // close the old cursor manually and replace it with the new one
    item_cursor_adater.getCursor().close();
    item_cursor_adater.changeCursor(item_cursor);
    // reset some cache data in the adapter
    item_cursor_adater.reset();
    // tell the list to refresh
    item_cursor_adater.notifyDataSetChanged();

    // to easy navigation, we set the focus the last selected item
    // set the last modified item as selected
    int selected_index = this.getItemPositionFromId(list, 
                                                    this.getCurrentContextFilter()
                                                        .getSelectedTaskId());

    list.setSelection(selected_index);
}

Some facts :

  • items.fetchItemForCurrentView() triggers a very heavy SQL query

  • this.getItemPositionFromId() loop on the entire ListView row by row to find the index of row with a given id.

  • the item_cursor_adapter extends SimpleCursorAdapter and overrides

    public View getView(int position, View convertView, ViewGroup parent)

Which is a pretty heavy method.

This method is called on the user demand quite often in the typical application use case, and waiting a second for the screen to refresh lower the user experience.

Do you have any suggestion on how this could be improved ?

Some ideas :

  • Use threads to load the data. But then, how to feed up the list afterwards ? How to make it appear not disturbing on the screen ?
  • Make reuse of some objects / use some cache I didn't think of.
  • Find a way for the list to update without reloading EVERYTHING
  • Change my implementation of the cursor adapter. Maybe extends a more efficient parent or use something better than getView ?
+4  A: 

You could get rid of all that code and just call requery() on the Cursor. As the name suggests, it re-runs the query that generated the Cursor in the first place. That will pick up the data changes and notify your list adapter about those changes. Your list adapter will update the screen for whichever rows are visible.

For a SimpleCursorAdapter, either override newView()/bindView(), or use a ViewBinder, or use setViewValue() and kin, as described in the documentation. You can override getView(), but then you have to do your own row-recycling stuff.

CommonsWare
Hi,Thansk for the newView()/bindView(),I'll try that. I forgot to say that I can't use requery() because a completly different SQL query is generated eash time.
e-satis