【问题标题】:Android ListView not cleared even after deleting all items即使删除所有项目后,Android ListView 也不会清除
【发布时间】:2013-02-08 19:50:30
【问题描述】:

更新:我每次都可以在我的 Galaxy S2 上复制这个问题(有和没有调试模式),但从来没有在模拟器上!

我在ListView(它使用CursorAdapter 的自定义实现)上使用上下文菜单让用户选择“全部删除”选项。选择此选项后,列表中显示的所有项目都应该从数据库中永久删除,然后在适配器上调用 changeCursor(..) 以强制更新列表。

然而,发生的情况是,即使在从数据库中删除记录并调用changeCursor(..) 之后,这些项目仍然可见。只有项目分隔符消失。只有在我触摸列表中的某个位置后,这些项目才会被清除。

当用户激活上下文菜单时: http://i.stack.imgur.com/ivFvJ.png

从数据库中删除并调用 changeCursor(..) 后: http://i.stack.imgur.com/CX6BM.png

我在使用 ListView (Android ListView items overlap while scrolling) 时遇到了另一个问题,而且我使用的是相同的 ListView,所以问题是否相关?是否有一些步骤可以强制ListView 在数据库更新后重绘?还是由于我如何实施解决方案的错误而没有自动发生?提前致谢!

这是ListView 的 XML

<ListView
        android:id="@+id/all_reminders_list"
        android:paddingLeft="4dp"
        android:paddingRight="4dp"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:layout_weight="1"
        android:layout_alignParentLeft="true"
        android:clickable="true"
        android:dividerHeight="1.0sp"
        android:animateLayoutChanges="true">

这是我自定义CursorAdapternewView(..)方法

public View newView(Context context, Cursor cursor, ViewGroup parent) {
    LayoutInflater inflater = LayoutInflater.from(parent.getContext());
    View view = inflater.inflate(R.layout.view_list_item, parent, false);
    return view;
}

我的CursorAdapterbindView(..)方法

public void bindView(View view, Context context, Cursor cursor) {

        TextView whatTextView = (TextView) view.findViewById(R.id.item_what_text);
        whatTextView.setText(cursor.getString(1));
        TextView whenTextView = (TextView) view.findViewById(R.id.item_when_text);


        if(cursor.getInt(9) != 0) // DONE_FLAG = 1 (completed)
        {
            //Arrow visibility
            ImageView arrow = (ImageView)view.findViewById(R.id.list_item_arrow);
            arrow.setVisibility(View.INVISIBLE);

            //Text color
            whatTextView.setTextColor(Color.LTGRAY);
            whenTextView.setTextColor(Color.LTGRAY);

            //WHEN text
            whenTextView.setText(TimeCalculationHelper.getCompletedTimeString(cursor.getLong(2)));
        }
        else // DONE_FLAG = 0
        {
            //Arrow visibility
            ImageView arrow = (ImageView)view.findViewById(R.id.list_item_arrow);
            arrow.setVisibility(View.VISIBLE);

            //Text color
            whatTextView.setTextColor(Color.BLACK);
            whenTextView.setTextColor(Color.BLACK);

            //WHEN text
            whenTextView.setText(TimeCalculationHelper.getTimeRemainingString(cursor.getLong(2)));


        }
}

这是我的 onContextItemSelected(..) 方法,来自 Activity,其中包含 ListView

public boolean onContextItemSelected(MenuItem item)
    {
        AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();
        ListView allRemindersList = (ListView)findViewById(R.id.all_reminders_list);

        switch (item.getItemId()) {
        case R.id.delete_item:
            //Delete the selected reminder from the database
            databaseHelper.deleteRowByID(info.id);

            //Refresh the main activity list
            ((ActiveRemindersAdapter) allRemindersList.getAdapter()).changeCursor(databaseHelper.getAllRemindersForList());
            return true;

        case R.id.delete_done:
            //Delete all reminders with DONE_FLAG = 1
            databaseHelper.deleteDoneReminders();

            //Refresh the main activity list
            ((ActiveRemindersAdapter) allRemindersList.getAdapter()).changeCursor(databaseHelper.getAllRemindersForList());
        }
        return false;
    }

【问题讨论】:

  • 更改光标后尝试添加((ActiveRemindersAdapter) allRemindersList.getAdapter()).notifyDataSetChanged()调用。
  • Nikita 是对的,最好使用支持库中的 CursorAdapter 并调用 swapCursor() 而不是 changeCursor()
  • @SaifuddinSarker,我也试过invalidateViews(),但它对我不起作用。

标签: android android-listview


【解决方案1】:

在光标更改后在适配器上调用 notifyDataSetChanged() 以重新加载视图。 如果运行预蜂窝设备,最好使用SupportLibrary 中的CursorAdapter

刚刚查看了代码。最好使用 swapCursor(),它会自动注册新的内容观察者并为您调用 notifyDataSetChanged()

来自 CursorAdapter 源代码。

/**
 * Change the underlying cursor to a new cursor. If there is an existing cursor it will be
 * closed.
 * 
 * @param cursor The new cursor to be used
 */
public void changeCursor(Cursor cursor) {
    Cursor old = swapCursor(cursor);
    if (old != null) {
        old.close();
    }
}

/**
 * Swap in a new Cursor, returning the old Cursor.  Unlike
 * {@link #changeCursor(Cursor)}, the returned old Cursor is <em>not</em>
 * closed.
 *
 * @param newCursor The new cursor to be used.
 * @return Returns the previously set Cursor, or null if there wasa not one.
 * If the given new Cursor is the same instance is the previously set
 * Cursor, null is also returned.
 */
public Cursor swapCursor(Cursor newCursor) {
    if (newCursor == mCursor) {
        return null;
    }
    Cursor oldCursor = mCursor;
    if (oldCursor != null) {
        if (mChangeObserver != null) oldCursor.unregisterContentObserver(mChangeObserver);
        if (mDataSetObserver != null) oldCursor.unregisterDataSetObserver(mDataSetObserver);
    }
    mCursor = newCursor;
    if (newCursor != null) {
        if (mChangeObserver != null) newCursor.registerContentObserver(mChangeObserver);
        if (mDataSetObserver != null) newCursor.registerDataSetObserver(mDataSetObserver);
        mRowIDColumn = newCursor.getColumnIndexOrThrow("_id");
        mDataValid = true;
        // notify the observers about the new cursor
        notifyDataSetChanged();
    } else {
        mRowIDColumn = -1;
        mDataValid = false;
        // notify the observers about the lack of a data set
        notifyDataSetInvalidated();
    }
    return oldCursor;
}

【讨论】:

  • 感谢您的回复。 notifyDataSetChanged() 的行为与对 changeCursor() 的调用有什么不同吗?将检查并确认它是否解决了我的问题。而且我只针对 ICS 和更新的设备。
  • 更新了答案。 notifyDataSetChanged() 是 BaseAdapter(CursorAdapter 从中扩展而来)的一种方法,用于强制重新加载视图。
  • 谢谢,但我尝试在changeCursor() 之后致电notifyDataSetChanged()。我也尝试打电话给swapCursor()。我仍然有完全相同的问题。
  • @PritinTyagaraj 您是否在删除后执行查询,然后再更改光标?你确定你设置的光标是空的吗?退出 cursor.getCount() 并查看包含多少行。
  • 是的,我已经保证了。 databaseHelper.getAllRemindersForList() 方法实际上执行了一个SELECT 查询并返回一个Cursor 作为结果。我注意到的另一件奇怪的事情是,我无法在模拟器中复制它,但我每次都能在我的 Galaxy S2 上复制它(无论是否处于调试模式)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-06-22
  • 1970-01-01
  • 2020-08-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多