Обновить родительский адаптер во вложенных адаптерах?

#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;
    }
}