RecyclerView适配器的notifyDataSetChanged方法无效

32

我扩展了

RecyclerView.Adapter<RecyclerView.ViewHolder>

当我打电话时:

mRecyclerView.getAdapter().notifyDataSetChanged();

没有发生任何事情。

刷新视图的唯一方法是重新设置适配器(查看此答案):

mRecyclerView.setAdapter(new MyAdapter(...));

我对这个解决方案有两个问题:

  1. 当我重新设置适配器时,屏幕上会出现闪烁
  2. 列表视图返回到第一个位置。

有什么想法吗?


你尝试过在MyAdapter中封装notifyDataSetChanged方法吗?例如:在MyAdapter中创建“myNotifyDataSetChanged”方法,然后从该方法调用this.notifyDataSetChanged()。保存MyAdapter引用并调用myAdapterRef.myNotifyDataSetChanged(),而不是myRecyiclerView.getAdapter().notifyDataSetChanged()。我不知道为什么这对我有用(我在ListView中遇到了这个问题)。 - bajicdusko
@helionprime 没有帮助 :( - David
好的,我的错。我忘记在onBindViewHolder方法中获取/使用更新后的数据了。但是闪烁效果怎么办?我该如何消除它? - David
好的,我的错。闪烁效果与在我的项目中将图像加载到imageViews有关。这是我正在使用的UniversalImageLoader(https://github.com/nostra13/Android-Universal-Image-Loader/issues/376)已知的问题。 - David
我很高兴你已经解决了它 :-). 如果你想尝试消除闪烁,可以在这个链接 https://github.com/bajicdusko/AndroidJsonProvider/tree/master/app/src/main/java/com/bajicdusko/ajp/tools 上尝试我为自己开发的图像加载器。它还支持缓存、优化、自动下载和在出现错误时显示默认图像。 - bajicdusko
2
你找到解决问题的方法了吗,David?我也遇到了同样的问题。 - Gaurav Arora
8个回答

37

如果notifyDataSetChanged()没有触发视图更新,那么你有可能忘记在RecyclerView上调用SetLayoutManager()(就像我一样!)。 只是别忘了这样做: Java 代码:

LinearLayoutManager layoutManager = new LinearLayoutManager(context ,LinearLayoutManager.VERTICAL, false);
recyclerView.setLayoutManager(layoutManager)

C#代码,我正在使用Xamarin。

var layoutManager = new LinearLayoutManager(Context, LinearLayoutManager.Vertical, false);
recyclerView.SetLayoutManager(layoutManager);

在调用recyclerView.SetAdapter(adapter)之前;

如果你更喜欢在xml中声明,这样你就不会在代码中忘记它,你也可以将这些行添加到你的recyclerView的xml中:

app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
android:orientation="vertical"

28
如果您的 getItemCount() 返回 0,则 notifyDataSetChanged() 不会起作用。确保在初始化适配器时,传递了有效的数据集。

4

要更新recyclerview,我们可以采取以下步骤:

  1. Create and set adapter again:

    adapter=new MyAdapter(...);
    mRecyclerView.setAdapter(adapter);
    
  2. Clear model list data and then notify:

    List<YourModel> tempModel=new ArrayList<>(modelList); 
    modelList.clear();   
    modelList.addAll(tempModel); 
    adapter.notifyDataSetChanged();
    

每次都无需创建新的适配器,只需要将新数据传递给现有的适配器即可。请参考下面的工作示例。 - akelec

4
根据javadocs的说法:如果你正在编写一个适配器,如果可以的话,始终使用更具体的change事件会更有效率。将notifyDataSetChanged()作为最后的手段。
public class NewsAdapter extends RecyclerView.Adapter<...> {    

private static List mFeedsList;
...

    public void swap(List list){
    if (mFeedsList != null) {
        mFeedsList.clear();
        mFeedsList.addAll(list);
    }
    else {
        mFeedsList = list;
    }
    notifyDataSetChanged();
}

我正在使用 Retrofit 来获取列表,在 Retrofit 的 onResponse() 中使用:

adapter.swap(feedList);

根据Javadocs文档:如果您正在编写一个适配器,如果可能的话,使用更具体的更改事件将始终更有效率。您在哪个Javadocs文档中找到这些信息? - Marian Paździoch
https://developer.android.com/reference/android/support/v7/widget/RecyclerView.Adapter.html#notifyDataSetChanged() - Akshay Goyal

4
在我的情况下,除此之外没有其他方法可行。当需要刷新一个RecyclerView时,我会执行以下操作:
array = getNewItems();                    // populates the list with new items
((MyAdapter) mAdapter).setValues(array);  // pass the new list to adapter !!!
mAdapter.notifyDataSetChanged();          // tell the adapter a data set has changed

MyAdapter中,我放置了数据的setter:
public void setValues(List<Item> items){
    this.items = items;
}

就是这样!

[请注意,如果不设置新值到适配器中,notifyDataSetChanged将无法正常工作。]


0

我是这样解决我的问题的:orderList是我传递给RecyclerView的列表。我们可以在列表中的某个位置添加项目,这里0是列表中的第一个位置。然后调用adapter.notifyDataSetChanged()。非常顺利地解决了问题。

1)orderList.add(0, String); 2)orderAdapter.notifyDataSetChanged();


0

notifyDataSetChanged() 应该在主线程中调用。


这似乎不是问题。 - Gabriel
1
谢谢。我的问题是服务中的监听器在其他线程上运行。 - David Vareka

0
想要分享一些东西,我曾经遇到过同样的问题。但是我的错误在于,每次都创建一个新的Adapter实例,然后对该新实例而不是旧实例进行notifysetDatachange()。
因此,请确保您通知setDataChange()的Adapter是旧的Adapter。 希望下面的示例有所帮助...
     MyAdapter mAdapter = new MyAdapter(...)

    mRecyclerView.setAdapter(mAdapter );

// TODO 
mAdapter.modifyData(....);
mAdapter.notifySetDataChange();


    MyAdapter extends baseAdapter {
     MyAdapter () {
    }
    modifyData(String[] listData) {

    }

    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接