Android Как применить несколько фильтров с androidx.recyclerview.widget.DiffUtil - PullRequest
2 голосов
/ 09 июля 2019

Я пытаюсь создать несколько фильтров для поиска данных в Recyclerview.

Например, в список покупок я могу поместить фильтр, как компьютеры, подпадающие под следующие критерии.

Бренд = яблоко, ScreenSize = от 10 до 13 дюймов, размер жесткого диска = от 250 до 500

Теперь у моей плоскости ViewModel будет список компьютеров со всеми этими критериями внутри класса модели 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 образца, RecyclerView может иметь DiffUtil , который можно использовать для эффективной фильтрации.

Но как отфильтровать ComputersData на основе таких критериев, как DiffUtil внутри адаптера RecyclerView?

brand = apple && screenSize = от 10 до 13, hardDisk = от 250 до 500

Любая идея будет высоко оценена!

1 Ответ

1 голос
/ 09 июля 2019

MainActivity

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.Обновлено Автор для дальнейшего использования

Приведенный выше ответ отлично работает в случае RecyclerView без ViewModels.Когда viewmodel приходит к изображению и RecyclerView прослушивает изменения в виртуальной машине, логика должна заключаться в том, чтобы обновлять отфильтрованный список новыми результатами в самом ViewModel.Таким образом, представление переработчика постоянно слушает обновления и постоянно обновляет данные.

В этом случае Разные утилиты могут не подходить.Довольно эффективный способ (как вопрос в Kotlin) с Filters

Я обнаружил, что фильтры намного проще, чем реализация Diff Util.

Для дальнейшего использования, пример применения фильтрас несколькими предикатами:

mViewModelObject является экземпляром объекта View Model

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

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

Как только новый список будет создан из нескольких критериев, обновите его в ViewModel.Так что Recycler View получит обновленный список.

...