0

I have a ListActivity that uses a CursorAdapter, and I can't get it to refresh. Here is some of the code I'm using:

public class ContactDetailsActivity extends ListActivity
{

    private ContactDetailsBroadcastReceiver mLvBroadcastReceiver;
    private Contact contact;


    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);


        contact = (Contact)getIntent().getSerializableExtra(AwesomeApp.CONTACT_OBJECT);

        if(contact == null) {
            DataUtils.log("Starting ContactDetailsActivity with NULL contact.");
            Toast.makeText(this, getString(R.string.no_contact_selected), Toast.LENGTH_SHORT).show();
            finish();
            return;
        }

        DataUtils.log("Starting ContactDetailsActivity with contact:" + contact.toString());
        setTitle(contact.getName());

        Cursor cursor = getContactDetailsCursor();
        startManagingCursor(cursor);

        setListAdapter(new ContactDetailsCursorAdapter(this, cursor));

        ListView lv = getListView();
        lv.setBackgroundResource(R.color.white);
        lv.setOnItemClickListener(new AdapterView.OnItemClickListener()
        {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id)
            {
                Toast.makeText(ContactDetailsActivity.this, "touched", Toast.LENGTH_SHORT).show();
            }
        });

        //Create broadcast receiver, to detect when a file upload has finished so we can update the pic status.
        mLvBroadcastReceiver = new ContactDetailsBroadcastReceiver();
    }

    private class ContactDetailsBroadcastReceiver extends BroadcastReceiver
    {
        @Override
        public void onReceive(Context context, Intent intent)
        {
            DataUtils.log("In BroadcastReceiver - ContactDetails");
            refreshListView();
        }
    }

My adapter basically just extends CursorAdapter in which I override newView and bindView:

public class ContactDetailsCursorAdapter extends CursorAdapter

I have a method inside ContactDetailsActivity called refreshListView() which I call in onResume(), and in the onReceive() method of my BroadcastReceiver

private void refreshListView()
{
    DataUtils.log("In ContactDetailsActivity refreshListView");
    ((ContactDetailsCursorAdapter)getListAdapter()).notifyDataSetChanged();

    this.getListView().invalidate();

    this.getListView().invalidateViews();
}

This is my getContactDetailsCursor() method:

private Cursor getContactDetailsCursor()
{
    AwesomeDbAdapter dbAdapter = AwesomeApp.getDbAdapter(this);
    Cursor c = dbAdapter.getRecentConversationsFromContact(contact.getId());
    DataUtils.log("New ContactDetails cursor has " + c.getCount() + " elements");
    return c;
}

As you can see, I've tried notifyDataSetChanged(), invalidate(), invalidateViews() and nothing seems to refresh the listview.

I'm totally out of ideas on how to get this to refresh. I'm seeing the logs and the method is being called both from onResume() and from the BroadcastReceiver's onReceive() methods.

Any pointers are appreciated!

Sandy
  • 2,572
  • 7
  • 40
  • 61

3 Answers3

1

This is what finally worked for me. As mentioned by @Kirill Shalnov, startManagingCursor() is deprecated however it's what I need to use. To be honest it's all a bit of guesswork, but alas does what I need.

@SuppressWarnings("deprecation")
private void refreshListView()
{
    DataUtils.log("In ContactDetailsActivity refreshListView");

    ContactDetailsCursorAdapter adapter = (ContactDetailsCursorAdapter)getListAdapter();

    Cursor oldCursor = null;
    if(adapter != null) {
        oldCursor = adapter.getCursor();
    }
    Cursor newCursor = getContactDetailsCursor();

    if(oldCursor != null) {
        stopManagingCursor(oldCursor);
        oldCursor.close();
    }
    startManagingCursor(newCursor);

    adapter = null;
    setListAdapter(new ContactDetailsCursorAdapter(this, newCursor));

    ListView listView = getListView();
    listView.setBackgroundResource(R.color.white);
    listView.invalidate();
    listView.invalidateViews();
}
Sandy
  • 2,572
  • 7
  • 40
  • 61
0

it seems you forgot to register the receiver: Register the receiver without registering it won't fire, register that receiver like below.

Example: In OnCreate:

ContactDetailsBroadcastReceiver receiver=new ContactDetailsBroadcastReceiver();
IntentFilter filter=new IntentFilter("android.net.wifi.STATE_CHANGE")
registerReceiver(receiver, filter);

In OnDestroy:

unregisterReceiver(receiver);
Rathan Kumar
  • 2,567
  • 2
  • 17
  • 24
  • Actually it is being registered and I see the log message when `onReceive()` method is called and `refreshListView()` is called. But the listview remains the same. This code wasn't included above for clarity, but this is mentioned. – Sandy Dec 14 '14 at 06:05
0

startManagingCursor(cursor);

It is deprecated way to work with cursor, you should to use Loaders, which can reload data automatically

Kirill Shalnov
  • 2,216
  • 1
  • 19
  • 21
  • In addition to this, my data is only used by my application, and as per http://stackoverflow.com/questions/18326954/how-to-read-an-sqlite-db-in-android-with-a-cursorloader it seems Loaders are more suited for ContentProvider data and not so much for other data not provided in this way. – Sandy Dec 14 '14 at 06:48
  • Loaders is solution to async loading cursor from data, for example, by using SQL, no matter did you use ContentProvider or not – Kirill Shalnov Dec 14 '14 at 17:53
  • @Sandy so, are you sure "notifyDataSetChanged()" should to requery cursor? I think that this method just initiate redrawing of listview with current cursor, and you have to requery data manually – Kirill Shalnov Dec 14 '14 at 17:59
  • I tried with a new cursor, via swapCursor, with no avail. – Sandy Dec 15 '14 at 02:12
  • Could you attach your getContactDetailsCursor(); implementation? – Kirill Shalnov Dec 15 '14 at 10:23
  • @Sandy may it can help - update your cursor into adapter - adapter.getCursor().requery(); in the refresh method or try to adapter.swapCursor(newCursor); adapter.notifyDataSetChanged(); – Kirill Shalnov Dec 15 '14 at 14:32