2014-10-29 74 views
34

我想为我的RecyclerView实现搜索功能。在更改的文本上,我想更改使用此小部件显示的数据。也许这个问题以前有人问或者是简单的,但我不知道如何来证明是数据的变化......RecyclerView更改数据集

我RecyclerView定义如下:

 // 1. get a reference to recyclerView 
    mRecyclerView = (RecyclerView)findViewById(R.id.recyclerView); 

    // 2. set layoutManger 
    mRecyclerView.setLayoutManager(new LinearLayoutManager(this)); 
    // 3. create an adapter 
    mAdapter = new ItemsAdapter(itemsData); 
    // 4. set adapter 
    mRecyclerView.setAdapter(mAdapter); 

而那我显示的数据是这样的:

ItemData itemsData[] = { new ItemData("Mary Richards"), 
     new ItemData("Tom Brown"), 
     new ItemData("Lucy London")   
}; 

所以,当我想给适配器另一组数据,另一个阵列(例如一个项目),我该怎么办?

+0

如果你想给另一个数组你可以创建一个新的'ItemsAdapter'它并再次调用'setAdapter'。 – 2014-10-29 16:44:09

回答

74

如果您在您的适配器有稳定的ID,您可以得到相当不错的效果(动画)如果您创建一个新的数组包含经过滤项,并调用

recyclerView.swapAdapter(newAdapter, false); 

使用swapAdapter提示RecyclerView之能重复使用查看者。 (与setAdapter相比,它必须回收所有视图并重新创建,因为它不知道新适配器与旧适配器设置了相同的ViewHolder)。

更好的方法是找到哪些项目被删除,并呼吁notifyItemRemoved(index)。不要忘记实际移除物品。这将让RecyclerView运行预测动画。假设你有一个内部使用一个ArrayList的适配器,实现应该是这样的:

// adapter code 
final List<ItemData> mItems = new ArrayList(); //contains your items 
public void filterOut(String filter) { 
    final int size = mItems.size(); 
    for(int i = size - 1; i>= 0; i--) { 
     if (mItems.get(i).test(filter) == false) { 
      mItems.remove(i); 
      notifyItemRemoved(i); 
     } 
    } 
} 

它会执行,如果你可以批量notifyItemRemoved调用和使用notifyItemRangeRemoved,而不是更好。它看起来某事像:(未测试)

public void filterOut(String filter) { 
    final int size = mItems.size(); 
    int batchCount = 0; // continuous # of items that are being removed 
    for(int i = size - 1; i>= 0; i--) { 
     if (mItems.get(i).test(filter) == false) { 
      mItems.remove(i); 
      batchCount ++; 
     } else if (batchCount != 0) { // dispatch batch 
      notifyItemRangeRemoved(i + 1, batchCount); 
      batchCount = 0; 
     } 
    } 
    // notify for remaining 
    if (batchCount != 0) { // dispatch remaining 
     notifyItemRangeRemoved(0, batchCount); 
    } 
} 

你需要扩展该代码添加先前过滤掉的项目,但现在应该是可见的(例如,用户删除过滤查询),但我觉得这个应该给出基本的想法。

请记住,每个通知项目调用会影响后面的项目(这就是为什么我要从尾遍历列表以避免它)。从最后遍历也有助于ArrayList的删除方法的性能(更少的项目转移)。

例如,如果您从头开始遍历列表并删除前两个项目。 你应该调用

notifyItemRangeRemoved(0, 2); // 2 items starting from index 0 

,或者如果你发货,由一个

notifyItemRemoved(0); 
notifyItemRemoved(0);//because after the previous one is removed, this item is at position 0 
+0

感谢您的回复,我会做出适合我需求的调整,但这是我基本需要的。你解释得很好。 – Sandra 2014-10-30 10:22:07

+1

“stable id”是什么意思?我的数据集更改,但我不知道以什么方式(一些新的项目可能会被添加,有些可能会被删除),但视图保持不变,所以我应该true或false传递swapAdapter? – 2016-06-10 08:06:01

2

刚刚重新初始化适配器:

mAdapter =新ItemsAdapter(newItemsData);

,或者如果你只需要删除添加一些特定的项目,而不是一个完整的列表

mAdapter。 notifyItemInserted(位置);

mAdapter.notiftyItemRemoved(位置);

22

一个这就是我的回答 - 从他的网站感谢伊万Skoric:http://blog.lovelyhq.com/creating-lists-with-recyclerview-in-android/

我创建了一个额外的方法在我的适配器类内:

public void updateList(List<Data> data) { 
    mData = data; 
    notifyDataSetChanged(); 
} 

然后每次y我们的数据发生了变化,您只需调用此方法传递新数据,并且您的视图应该改变以反映它。

+0

notifyDataSetChanged()杀死所有动画,只适用于大列表。 – Davidea 2016-07-27 12:50:00

+0

@Davidea ...这是RecyclerView的典型用例 – 2017-03-06 10:22:04

+0

recyclerview仅将您的可见视图保留在内存中,并在您将它们从屏幕上滚动时释放它们。从内存角度来看,与列表视图相比,它非常高效。它们的操作与列表视图相似。您可以在这里阅读recyclerview文档:https://developer.android.com/reference/android/support/v7/widget/RecyclerView.html – Simon 2017-03-07 11:18:59

0

作为ygit回答,swapAdapter是有趣的,当你必须改变整个内容。

但是,在我的FlexibleAdapter中,您可以使用updateDataSet更新项目。您甚至可以配置适配器以调用notifyDataSetChanged或同步动画(默认启用)。那是因为notifyDataSetChanged杀死了所有的动画,但是对于大列表来说是很好的选择。

请看看说明,demoApp和Wiki页面:https://github.com/davideas/FlexibleAdapter