每次删除项目时,RecyclerView 最后一项都会闪烁

RecyclerView last item blinks every time an item is removed

我正在使用带有 RecyclerView 的游标加载器,其他一切正常,除了每次我从 RecyclerView 中删除一个项目时,最后一个项目会闪烁,就像这样

last item blinks

我的删除代码是

public void deleteData(long id){
    Uri uri = ContentUris.withAppendedId(URI, id);
    getContentResolver().delete(uri, null, null);
}

刷卡验证码:

deleteData(viewHolder.getItemId());

请注意,我还有另一个 activity 使用相同的 RecyclerAdapterContentProvider 和布局代码,甚至大多数实现和方法方法都是相同的,但那个有效完全没有眨眼,所以这对我来说是一个很奇怪的情况。

是否有导致此问题的具体原因?我已经试过禁用动画

recyclerView.getItemAnimator().setChangeDuration(0);

((DefaultItemAnimator) recyclerViewObject.getItemAnimator()).setSupportsChangeAnimations(false);

但是 none 有效,更不用说我确实希望动画有效。

编辑:断点上传:

创建时:

"main@4668" prio=5 tid=0x2 nid=NA runnable java.lang.Thread.State: RUNNABLE at com.jackz314.todo.HistoryActivity.onCreateLoader(HistoryActivity.java:803) at android.support.v4.app.LoaderManagerImpl.createLoader(LoaderManager.java:539) at android.support.v4.app.LoaderManagerImpl.createAndInstallLoader(LoaderManager.java:548) at android.support.v4.app.LoaderManagerImpl.initLoader(LoaderManager.java:603) at com.jackz314.todo.HistoryActivity.displayAllNotes(HistoryActivity.java:394) at com.jackz314.todo.HistoryActivity.deleteExpiredNotes(HistoryActivity.java:767) at com.jackz314.todo.HistoryActivity.onCreate(HistoryActivity.java:129)
at android.app.Activity.performCreate(Activity.java:6975) at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1213) at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2770) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2892) at android.app.ActivityThread.-wrap11(ActivityThread.java:-1) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1593)
at android.os.Handler.dispatchMessage(Handler.java:105) at android.os.Looper.loop(Looper.java:164) at android.app.ActivityThread.main(ActivityThread.java:6541) at java.lang.reflect.Method.invoke(Method.java:-1) at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)

onDelete(删除项目):

"main@4668" prio=5 tid=0x2 nid=NA runnable java.lang.Thread.State: RUNNABLE at com.jackz314.todo.HistoryActivity.deleteData(HistoryActivity.java:791) at com.jackz314.todo.HistoryActivity.onSwiped(HistoryActivity.java:434) at android.support.v7.widget.helper.ItemTouchHelper.run(ItemTouchHelper.java:686) at android.os.Handler.handleCallback(Handler.java:789) at android.os.Handler.dispatchMessage(Handler.java:98) at android.os.Looper.loop(Looper.java:164) at android.app.ActivityThread.main(ActivityThread.java:6541) at java.lang.reflect.Method.invoke(Method.java:-1) at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)

希望这些有帮助

编辑: 稍微查了一下,发现最后一项居然没有闪烁,好像是RecyclerView先改成了length/size, 截掉一段与被删除项大小相等的部分(deleting), 使最后一项(取决于被删除项的大小)暂时不可见, 然后 RecyclerView删除应该在开头删除的项目。我仍在努力,想弄清楚是因为我在某处弄乱了订单还是其他原因。

让我们在与RecyclerViewAdapter 绑定的数据对象处放置断点,并检查数据是否闪烁。在大多数情况下,像这种情况,我意识到数据可能受到影响并使视图更改无法控制。因为不知道你是怎么处理数据的,所以没法给你更详细的解答。

您是否尝试过禁用动画?

adapter.setHasStableIds(true);
recyclerView.setItemAnimator(null);

Jackz 下面的代码在 DetailsActivity 中,它有一个 btnDelete,它触发并转到 DBHelper 并删除记录,returns DetailsActivity 然后调用 ListActivity 以从基于列表的列表中删除项目在位置上 NOT 记录 ID

   private void addListenerOnButtonDelete() {
    btnDelete.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {

            // Calls the Method deleteDBRow in DatabaseHelper
            // which acts on the TABLE_INFO to remove a record by getting the record ID
            helper.deleteDBRow(String.valueOf(dbList.get(position).getID()));
            ListActivity.removeListRow(position);
            // Code line above calls Method in ListActivity to notify recycler view of changes
            // NOTICE the List keeps items by position not ID <== READ
            etWebSite.setText("");
            etUN.setText("");
            etPW.setText("");
            etSecQuestion.setText("");
            etSecAnswer.setText("");
            etNotes.setText("");

            Intent intent = new Intent(DetailsActivity.this, ListActivity.class);
            startActivity(intent);
        }
    });
}

这是与适配器对话的 ListActivity 中的代码

    // This method is called from DetailsActivity and notifies Recycler View that the DB was changed
// and the method makes the same changes to the Recycler View kind of a sync of DB and Recycler View
public static void removeListRow(int position) {
    dbList.remove(position);
    mAdapter.notifyItemRemoved(position);
    mAdapter.notifyItemRangeChanged(position, dbList.size());
}

我遇到了和你一样的问题。我认为问题在于每次我们从数据库中删除内容时 CursorLoader 都会重新启动,因此每次都会触发 onLoadFinished 并交换游标。

如果我们将数据从游标加载到列表并将其传递给适配器,则问题可能是 "solved"。不过,我认为这是一种解决方法,而不是真正的解决方案。

终于明白了!

又是一个愚蠢的错误,一点都不复杂,我一直在想,为什么我只有这个activity有这个问题,而我以前的没有,我突然意识到布局在这两个活动是不同的,原来我将 RecyclerView 的高度设置为 wrap_content,所以我想发生了什么,布局告诉系统将内容包装在 RecyclerView ,当你删除一个项目时,它在技术上不再存在,所以,即使我有删除项目的动画,项目也会立即从布局级别删除,这就是为什么 Android 调整了 RecyclerView的高度,然后删除item,实际发生的是,由于RecyclerView设置为wrap_content,它删除后立即删除视图(项目)的位置,而不是之后动画,这就是它看起来像眨眼的原因。

无论如何,解决方法就是将 RecyclerView 的高度从 wrap_content 更改为任何其他值,如果您像我一样使用 ConstraintLayout,只需更改高度 0dp,然后将 RecyclerView 约束到其他东西或边缘。

感谢所有试图帮助我解决问题的人,我承认这是我遇到过的最愚蠢但最令人沮丧的问题之一。

我相信还有其他人也遇到了同样的问题,所以去检查高度是否设置为wrap_content

我也有同样的问题,这让我抓狂。

你的解决方案对我不起作用,可能是因为我的 RecyclerViewer 在 LinearLayout 中?

到目前为止我发现的唯一解决方法是禁用那样的动画

cardRecyclerView.itemAnimator = null

但我真的很想重新启用动画,因为没有它会有点不稳定。

这是我的布局,有人知道如何避免在移除卡片时最后一项闪烁吗?提前谢谢你

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:id="@+id/mainLayout"
              android:orientation="vertical"
              android:layout_width="match_parent"
              android:fitsSystemWindows="true"
              android:layout_height="wrap_content">
    <fragment
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:name="com.bendk97.platenumber.activities.main.Toolbar"/>
    <fragment
            android:id="@+id/search_bar"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:name="com.bendk97.platenumber.activities.main.SearchBar"/>
    <ProgressBar
            style="@style/Widget.AppCompat.ProgressBar"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:indeterminateTint="@android:color/white"
            android:id="@+id/progressBar" android:visibility="invisible"/>
    <android.support.v7.widget.RecyclerView
            android:id="@+id/recycler"
            android:layout_width="match_parent"
            android:layout_height="wrap_content">
    </android.support.v7.widget.RecyclerView>
</LinearLayout>