Android 如何使用 androidx.recyclerview.widget.DiffUtil 应用多个过滤器

Android How to apply multiple filters with androidx.recyclerview.widget.DiffUtil

我正在尝试创建实现多个过滤器以在 Recyclerview 中搜索数据。

例如,在购物清单中,我可以筛选符合以下条件的计算机。

品牌 = 苹果,屏幕尺寸 = 10 到 13 英寸,硬盘大小 = 250 到 500

现在我的平面 ViewModel 将在模型 class ResponseBase 中包含包含所有这些条件的计算机列表,这是我从后端获取的。

class ItemViewModel : ViewModel() {

var mResponse : MutableLiveData<ResponseBase>? = null

fun getData() : MutableLiveData<ResponseBase> {
    if(null == mResponse) {
       mResponse = NetworkProcessor().loadSearchData()
    }
    return mResponse as MutableLiveData<ResponseBase>
  }
}

ResponseBase.kt

data class ResponseBase(
    val matches: List<ComputersData>
)

ComputersData.kt

data class ComputersData(
    val brand: String,
    val screenSize: Int,
    val hardDisk: Int,
    val processor: String,
    val display_name: String,
    val ram: Int,
)

现为Android Sunflower sample, RecyclerView can have DiffUtil,可用于高效过滤

但是如何使用 RecyclerView Adapter 中的 DiffUtil 根据这样的标准过滤 ComputersData?

brand = apple && screenSize = 10 to 13 , hardDisk = 250 to 500

任何想法将不胜感激!

主要活动

public class MainActivity extends AppCompatActivity {

private RecyclerView mRecyclerView;
private EmployeeRecyclerViewAdapter mRecyclerViewAdapter;
private List<Employee> employeeList;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    employeeList = DummyEmployeeDataUtils.getEmployeeList();
    mRecyclerViewAdapter = new EmployeeRecyclerViewAdapter(
            employeeList);
    mRecyclerView = (RecyclerView) findViewById(R.id.recycler_view);
    mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
    mRecyclerView.setAdapter(mRecyclerViewAdapter);
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.sort_menu, menu);
    return super.onCreateOptionsMenu(menu);
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
        case R.id.age_above_employees:        
    mRecyclerViewAdapter.updateEmployeeListItems(DummyEmployeeDataUtils.getEmployessWithAgeAbove50());
            return true;
    }
    return super.onOptionsItemSelected(item);
   }
 }

创建带有年龄的虚拟员工列表

public class DummyEmployeeDataUtils {

public static List<Employee> getEmployessWithAgeAbove50() {
    final List<Employee> employeeList = getEmployeeList();
    final List<Employee> filteredEmployees = new ArrayList<>();
    for (int i = 0; i < employeeList.size(); i++) {
        if (employeeList.get(i).getAge() > 50)
            filteredEmployees.add(employeeList.get(i));
    }
    return filteredEmployees;
}

public static List<Employee> getEmployeeList() {
    final List<Employee> employees = new ArrayList<>();

    employees.add(new Employee(1, "Employee 1", "Developer", 12));
    employees.add(new Employee(2, "Employee 2", "Tester", 52));
    employees.add(new Employee(3, "Employee 3", "Support", 72));
    employees.add(new Employee(4, "Employee 4", "Sales Manager", 11));
    employees.add(new Employee(5, "Employee 5", "Manager", 64));
    employees.add(new Employee(6, "Employee 6", "Team lead", 99));
    employees.add(new Employee(7, "Employee 7", "Scrum Master", 89));
    employees.add(new Employee(8, "Employee 8", "Sr. Tester", 23));
    employees.add(new Employee(9, "Employee 9", "Sr. Developer", 21));
    return employees;
  }
}

这是我们的适配器

public class EmployeeRecyclerViewAdapter extends
    RecyclerView.Adapter<EmployeeRecyclerViewAdapter
            .ViewHolder> {

private List<Employee> mEmployees = new ArrayList<>();

public EmployeeRecyclerViewAdapter(List<Employee> employeeList) {
    this.mEmployees.addAll(employeeList);
}

@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    final LayoutInflater inflater = LayoutInflater.from(parent.getContext());
    final View view = inflater.inflate(R.layout.list_item, parent, false);
    return new ViewHolder(view);
}

@Override
public void onBindViewHolder(ViewHolder holder, int position) {
    final Employee employee = mEmployees.get(position);
    holder.bindView(employee);
}

public void updateEmployeeListItems(List<Employee> employees) {
    final EmployeeDiffCallback diffCallback = new EmployeeDiffCallback(this.mEmployees, employees);
    final DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(diffCallback);
    this.mEmployees.clear();
    this.mEmployees.addAll(employees);
    diffResult.dispatchUpdatesTo(this);
}

@Override
public int getItemCount() {
    return mEmployees.size();
}

public static class ViewHolder extends RecyclerView.ViewHolder {

    private final TextView role;
    private final TextView name;
    private final TextView age;

    public ViewHolder(View itemView) {
        super(itemView);
        name = (TextView) itemView.findViewById(R.id.employee_name);
        role = (TextView) itemView.findViewById(R.id.employee_role);
        age = (TextView) itemView.findViewById(R.id.employee_age);
    }

    void bindView(Employee employee) {
        name.setText(employee.getName());
        role.setText(employee.getRole());
        age.setText("Age ".concat(employee.getAge()+""));
    }
  }
}

这是 DiffUtil 适配器

public class EmployeeDiffCallback extends DiffUtil.Callback {

private final List<Employee> mOldEmployeeList;
private final List<Employee> mNewEmployeeList;

public EmployeeDiffCallback(List<Employee> oldEmployeeList, List<Employee> newEmployeeList) {
    this.mOldEmployeeList = oldEmployeeList;
    this.mNewEmployeeList = newEmployeeList;
}

@Override
public int getOldListSize() {
    return mOldEmployeeList.size();
}

@Override
public int getNewListSize() {
    return mNewEmployeeList.size();
}

@Override
public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {
    return mOldEmployeeList.get(oldItemPosition).getId() == mNewEmployeeList.get(
            newItemPosition).getId();
}

@Override
public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {
    final Employee oldEmployee = mOldEmployeeList.get(oldItemPosition);
    final Employee newEmployee = mNewEmployeeList.get(newItemPosition);

    return oldEmployee.getName().equals(newEmployee.getName());
}

@Nullable
@Override
public Object getChangePayload(int oldItemPosition, int newItemPosition) {
    // Implement method if you're going to use ItemAnimator
    return super.getChangePayload(oldItemPosition, newItemPosition);
   }
}

更新的答案

编辑 Manoj 的回答。由作者更新以供将来参考

以上答案适用于没有 ViewModel 的 RecyclerView。 一旦 viewmodel 出现并且 RecyclerView 监听 VM 中的变化,逻辑应该是用 ViewModel 本身的新结果更新过滤列表。 这样回收站视图会一直监听更新并保持数据更新。

在这种情况下,Diff Utils可能就派不上用场了。 相当有效的方法(因为问题在 Kotlin 中)是 Filters

我发现过滤器比 Diff Util 实施简单得多。

为了将来参考,具有多个谓词的示例过滤器方法如下

mViewModelObject是ViewModel对象的实例

val valueOne =  mViewModelObject.criteriaOne.value
val valueTwo =  mViewModelObject.criteriaTwo.value

 val newList  = originalList.filter {
                    it.listVariableABC == valueOne 
                    &&
                    it.listVariablePQR == valueTwo
}

根据多个条件创建新列表后,在 ViewModel 中更新相同的列表。这样 Recycler View 就会得到更新的列表。