【问题标题】:Refresh ListView from ListActivity with CursorAdapter使用 CursorAdapter 从 ListActivity 刷新 ListView
【发布时间】:2026-02-03 23:35:01
【问题描述】:

我有一个使用 CursorAdapter 的 ListActivity,但我无法让它刷新。这是我正在使用的一些代码:

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();
        }
    }

我的适配器基本上只是扩展了CursorAdapter,在其中我覆盖了newViewbindView

public class ContactDetailsCursorAdapter extends CursorAdapter

我在ContactDetailsActivity 中有一个名为refreshListView() 的方法,我在onResume() 和我的BroadcastReceiver 的onReceive() 方法中调用它

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

    this.getListView().invalidate();

    this.getListView().invalidateViews();
}

这是我的getContactDetailsCursor() 方法:

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;
}

如您所见,我尝试了notifyDataSetChanged()invalidate()invalidateViews(),但似乎没有任何东西可以刷新列表视图。

我完全不知道如何刷新它。我正在查看日志,并且正在从 onResume() 和 BroadcastReceiver 的 onReceive() 方法调用该方法。

任何指针表示赞赏!

【问题讨论】:

    标签: android android-listview listactivity listadapter android-cursoradapter


    【解决方案1】:

    这最终对我有用。正如@Kirill Shalnov 所提到的,startManagingCursor() 已被弃用,但这是我需要使用的。老实说,这都是一些猜测,但可惜的是我需要的。

    @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();
    }
    

    【讨论】:

      【解决方案2】:

      您似乎忘记注册接收方: 注册接收器而不注册它不会触发,如下注册接收器。

      示例: 在 OnCreate 中:

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

      在 OnDestroy 中:

      unregisterReceiver(receiver);
      

      【讨论】:

      • 实际上它正在注册,当onReceive() 方法被调用和refreshListView() 被调用时,我看到了日志消息。但列表视图保持不变。为清楚起见,上面未包含此代码,但已提及。
      【解决方案3】:

      startManagingCursor(光标);

      不推荐使用光标的方式,你应该使用Loaders,它可以自动重新加载数据

      【讨论】:

      • 除此之外,我的数据仅由我的应用程序使用,并且根据*.com/questions/18326954/… 看来,加载程序更适合 ContentProvider 数据,而不适合以这种方式提供的其他数据。
      • Loaders是从数据中异步加载游标的解决方案,例如使用SQL,不管你有没有使用ContentProvider
      • @Sandy 所以,你确定“notifyDataSetChanged()”应该重新查询游标吗?我认为这个方法只是用当前光标启动列表视图的重绘,你必须手动重新查询数据
      • 我尝试通过 swapCursor 使用新光标,但无济于事。
      • 你能附上你的 getContactDetailsCursor();实施?