#java #android #android-recyclerview #nestedrecyclerview
#java #Android #android-recyclerview #nestedrecyclerview
Вопрос:
У меня есть вложенные адаптеры для двух видов RecyclerViews примерно так:
Родительский адаптер:
public class ParentAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
public static ArrayList<ParentItem> parentItemList;
private RecyclerView.RecycledViewPool viewPool = new RecyclerView.RecycledViewPool();
private com.example.todotestapp.ChildAdapter childAdapter;
public ParentAdapter(ArrayList<ParentItem> parentItemList) {
this.parentItemList = parentItemList;
}
public class ParentViewHolder extends RecyclerView.ViewHolder {
private RecyclerView childRecyclerView;
public ParentViewHolder(final View parentView) {
super(parentView);
childRecyclerView = parentView.findViewById(R.id.child_recyclerview);
}
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
Context context = parent.getContext();
LayoutInflater inflater = LayoutInflater.from(context);
View parentView = inflater.inflate(R.layout.parent_layout, parent, false);
return new ParentViewHolder(parentView);
}
@Override
public void onBindViewHolder(final RecyclerView.ViewHolder holder, final int position) {
final ParentItem someParentItem = parentItemList.get(position);
ArrayList<ChildItem> childItemList = someParentItem.getChildItemList();
RecyclerView childRecyclerView = ((ParentViewHolder) holder).childRecyclerView;
LinearLayoutManager layoutManager = new LinearLayoutManager(childRecyclerView.getContext());
layoutManager.setInitialPrefetchItemCount(childItemList.size());
childAdapter = new com.example.todotestapp.ChildAdapter(childItemList);
childRecyclerView.setLayoutManager(layoutManager);
childRecyclerView.setAdapter(childAdapter);
childRecyclerView.setRecycledViewPool(viewPool);
}
@Override
public int getItemCount() {return parentItemList.size(); }
}
Дочерний адаптер:
public class ChildAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private ArrayList<ChildItem> childItemList;
public ChildAdapter(ArrayList<ChildItem> childItemList) {
this.childItemList = childItemList;
}
public class ChildViewHolder extends RecyclerView.ViewHolder {
CheckBox childCheckBox;
public ChildViewHolder(final View childView) {
super(childView);
childCheckBox = childView.findViewById(R.id.child_checkbox);
childCheckBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
ChildItem checkedChildItem = childItemList.get(getAdapterPosition());
ParentItem parentItemOfCheckedChildItem = checkedChildItem.getParentItem();
int parentAdapterPos = ParentAdapter.parentItemList.indexOf(parentItemOfCheckedChildItem);
int mainPos = MainActivity.mainParentItemList.indexOf(parentItemOfCheckedChildItem);
ArrayList<ChildItem> aChildItemList = parentItemOfCheckedChildItem.getChildItemList();
aChildItemList.remove(checkedChildItem);
childItemList.remove(checkedChildItem);
parentItemOfCheckedChildItem.setChildItemList(aChildItemList);
ParentAdapter.parentItemList.set(parentAdapterPos, parentItemOfCheckedChildItem);
MainActivity.mainParentItemList.set(mainPos, parentItemOfCheckedChildItem);
MainActivity.mainChildItemList.remove(checkedChildItem);
checkedChildItem.setIsChecked(true);
MainActivity.mainChildItemList.add(checkedChildItem);
ParentItem checkedParentItem = ParentAdapter.parentItemList.get(ParentAdapter.parentItemList.size() - 1);
checkedParentItem.addToChildItemList(checkedChildItem);
ParentAdapter.parentItemList.set(ParentAdapter.parentItemList.size() - 1, checkedParentItem);
notifyDataSetChanged();
}
});
}
}
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
Context context = parent.getContext();
LayoutInflater inflater = LayoutInflater.from(context);
View childView = inflater.inflate(R.layout.child_layout, parent, false);
return new ChildViewHolder(childView);
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
final ChildItem aChildItem = childItemList.get(position);
}
@Override
public int getItemCount() {return childItemList.size();}
}
Я знаю, что дочерний адаптер довольно грязный, но у меня возникают проблемы с обработкой данных. Я хотел бы удалить checkedChildItem из его текущего родительского элемента, добавить его в новый родительский элемент, а затем обновить данные. Мой текущий код выполняет первые два шага (удаляет дочерний элемент из списка дочерних элементов исходного родительского элемента и добавляет его в новый родительский элемент), но отображает данные только после обновления действия.
Я попытался передать данные родительскому адаптеру с помощью метода «updateDataAfterChecked», но я все еще не могу его обновить, поскольку ChildItemViewHolder является статическим контекстом, а notifyDataSetChanged() — нет, поэтому я не могу найти способ обновить родительский адаптер, не переходя к другому действию и обратно. Есть предложения?
————————————РЕДАКТИРОВАТЬ—————————————-
Я смог получить доступ к .notifyDataSetChanged(), используя LiveData для ParentItemList, но дочерний элемент по-прежнему не отображается во втором родительском элементе, пока страница не будет обновлена (если я вызываю finish(), затем startActivity(GetIntent()), все работает так, как должно, за исключением того, что это вызываетнеприятный эффект, который мне не нравится). Есть предложения, которые помогут устранить эту проблему? Спасибо.
————————————РЕДАКТИРОВАТЬ—————————————-
То, к чему я стремлюсь, это что-то вроде того, что делает приложение Google Tasks (Android) — если вы отметите элемент, он будет удален с даты и добавлен в «Завершено» в режиме реального времени; Я не знаю, помогает ли эта информация с ответами вообще, но я подумал, что это будетстоит упомянуть.
Ответ №1:
Вы должны использовать Sectioned-RecyclerView вместо RecyclerView.
См. Приведенный ниже код: https://github.com/IntruderShanky/Sectioned-RecyclerView
Надеюсь, приведенная выше ссылка поможет вам.
Комментарии:
1. Не хочу показаться грубым, но этот адаптер в последний раз обновлялся четыре года назад … если вы посмотрите на исходный код … это не самая эффективная реализация (notifyDataSetChanged создает новый список, преобразует его, а затем отправляет уведомление, просто чтобы назвать одну вещь, все это происходит в MainThread).
2. Я согласен с вашим комментарием; Я больше ищу способ просто внедрить что-то в свой существующий код. Необходимость внедрять целую новую библиотеку и (в основном) воссоздавать приложение не обязательно идеально.
Ответ №2:
Понял это с помощью ViewModels и MutableLiveData.
In MainActivity:
public class MainActivity extends AppCompatActivity implements LifecycleOwner {
public static ChildViewModel childViewModel;
public static ArrayList<ChildItem> childAdapterData;
private ParentAdapter parentAdapter;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
setViewModel();
// Populate childAdapterData in setAdapter()
setAdapter();
setRecyclerView();
updateViewModel();
}
...
public static void updateViewModel() {
childViewModel.getChildItemLiveData().setValue(childAdapterData);
}
public void setViewModel() {
childViewModel = new ViewModelProvider(this).get(ChildViewModel.class);
final Observer<ArrayList<ChildItem>> observer = new Observer<ArrayList<ChildItem>>() {
@Override
public void onChanged(ArrayList<ChildItem> childItems) {
// Do things
// Don't have to do notifyDataSetChanged--also notifyItemRangeChanged(), etc.
parentAdapter.notifyDataSetChanged();
}
};
childViewModel.getChildItemLiveData().setValue(childAdapterData);
childViewModel.getChildItemLiveData().observe(this, observer);
}
}
В дочернем адаптере:
public class ChildAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private ArrayList<ChildItem> childItemList;
public ChildAdapter(ArrayList<ChildItem> childItemList) {
this.childItemList = childItemList;
}
public class ChildViewHolder extends RecyclerView.ViewHolder {
CheckBox childCheckBox;
public ChildViewHolder(final View childView) {
super(childView);
childCheckBox = childView.findViewById(R.id.child_checkbox);
childCheckBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
ChildItem checkedChildItem = childItemList.get(getAdapterPosition());
// Remove from ParentItem A
...
// Add to ParentItem B
...
MainActivity.childAdapterData.set(parentItemAPosition, parentItemA);
MainActivity.childAdapterData.set(parentItemBPosition, parentItemB);
MainActivity.updateViewModel();
}
});
}
}
...
}
Наконец, ViewModel
public class ChildViewModel extends ViewModel {
public MutableLiveData<ArrayList<ChildItem>> childItemLiveData;
public MutableLiveData<ArrayList<ChildItem>> getChildItemLiveData() {
if(childItemLiveData == null) {
childItemLiveData = new MutableLiveData<>();
}
return childItemLiveData;
}
}