Я пытаюсь создать несколько фильтров для поиска данных в Recyclerview.
Например, в списке покупок я могу отфильтровать компьютеры, подпадающие под следующие критерии.
Марка = яблоко, размер экрана = от 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>
)
КомпьютерыData.kt
data class ComputersData(
val brand: String,
val screenSize: Int,
val hardDisk: Int,
val processor: String,
val display_name: String,
val ram: Int,
)
Теперь, согласно образцу Android-подсолнух, RecyclerView может иметь DiffUtil, который можно использовать для эффективной фильтрации.
Но как фильтровать ComputersData на основе подобных критериев с помощью DiffUtil внутри адаптера RecyclerView?
brand = apple && screenSize = от 10 до 13 , hardDisk = от 250 до 500
Любая идея будет высоко оценена!
какие-либо образцы или ссылки для справки, пожалуйста?
DiffUtil — это служебный класс, который может вычислить разницу между двумя списками и вывести список операций обновления, которые преобразуют первый список во второй. от developer.android.com/reference/android/support/v7/util/…. Если вы хотите отфильтровать список по своим критериям, вы должны отфильтровать его самостоятельно.
Я опубликую один на Java, это нормально для вас?
Конечно, пожалуйста, продолжайте..
Братан, пожалуйста, проверьте ответ, если вам нужна помощь, просто пропингуйте комментарий
Конечно. Спасибо за ваш вклад. Дай мне проверить.
Основная деятельность
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. Как только модель просмотра приходит к изображению, а RecyclerView прослушивает изменения в виртуальной машине, логика должна заключаться в обновлении отфильтрованного списка новыми результатами в самой ViewModel. Таким образом, представление ресайклера все время прослушивает обновления и обновляет данные.
В этом случае Диф Утилиты может не подойти. Достаточно эффективный способ (поскольку вопрос в Котлине) - с Фильтры
Я обнаружил, что фильтры намного проще, чем реализация 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 получит обновленный список.
Для EmployeeDiffCallback в методе areItemsTheSame образец сравнивает getId . Является ли это членом класса Employee? Или какие-то методы по умолчанию?
@Sreehari, братан, ты видел класс DTO, я только что создал ключ идентификатора для сотрудника для сравнения, вы также можете сравнить, используя какой-либо другой параметр сотрудника
:Спасибо за ответ! Ваша логика отлично работает без реализации ViewModel, если пользовательский интерфейс не слушает ViewModel. Несмотря на то, что логика фильтрует идеально, когда ViewModel приходит к picture , данные возвращаются обратно с данными из ViewModel. Поэтому я манипулировал ViewModel, чтобы иметь 2 набора. Первый отфильтрованный, второй оригинальный! Это работает как очарование. Даю +10 к вашему ведру за потрясающее объяснение.
Сначала вы должны создать отфильтрованный список, а затем отправить его в diffutil с помощью submitlist.