从嵌套的RecyclerView中删除项目

问题描述 投票:0回答:1

我已经解决了这个问题好几个小时了。我有一个嵌套的RecyclerView(即包含一个内部Recycler视图的RecyclerView)。父回收者视图和子回收者视图都是动态的。我遇到的问题是,当发生CRUD(尤其是删除)时,我找不到正确的方式通知子(内部)回收者视图的方法。起初它可以正常运行,但是随后我从“您必须是直接下降视图”或getAdapterPosition返回-1或只是位置不正确的情况中得到了各种随机错误。我认为我的实现是非常标准的,所以我问什么是通知内部回收者视图的正确方法。

我几乎要回到我以前的实现中,该实现涉及到一系列包含回收视图的片段,但是我对这种设计的性能提出了质疑。我的代码如下:

家长RecyclerView

public class RecipeRecyclerAdapter extends RecyclerView.Adapter<RecipeRecyclerAdapter.ViewHolder>
{
    public interface OnRecipeRecyclerListener
    {
        //--------------------------- Proxy methods for OnDishRecyclerListener -----------------

        void renameDish(int DishPosition, int RecipePosition);

        void deleteDish(int DishPosition, int RecipePosition);


        //--------------------------- OnRecipeRecyclerListener methods ----------------------------

        void deleteRecipe(int RecipePosition);

        void renameRecipe(int RecipePosition);

    }

    //Recycler Pool and tools
    private RecyclerView.RecycledViewPool viewPool = new RecyclerView.RecycledViewPool();

    //Recycler Parameters
    private ArrayList<Recipe> allRecipes;
    private Context context;


    //Listener
    @Setter
    private OnRecipeRecyclerListener onRecipeRecyclerListener;


    public RecipeRecyclerAdapter(Context context, ArrayList<Recipe> allRecipes)
    {
        this.allRecipes = allRecipes;
        this.context = context;
    }

    @NonNull
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType)
    {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.card_Recipe, parent, false);

        return new RecipeRecyclerAdapter.ViewHolder(view, onRecipeRecyclerListener, context);
    }

    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position)
    {
        Recipe Recipe = allRecipes.get(position);  

        holder.RecipeName.setText(Utils.colourFirstLetter(context, Recipe.getRecipeName(), R.color.progressFxBar));
        holder.RecipeDate.setText(Utils.getDate(Recipe.getTimestamp()));

        // Create layout manager with initial prefetch item count
        LinearLayoutManager layoutManager = new LinearLayoutManager(
                holder.DishsRecycler.getContext(),
                LinearLayoutManager.VERTICAL,
                false
        );
        layoutManager.setInitialPrefetchItemCount(Recipe.getDishs().size());

        DishRecyclerAdapter DishsRecyclerAdapter = new DishRecyclerAdapter(Recipe.getDishs(), holder, context);        

        holder.DishsRecycler.setLayoutManager(layoutManager);
        holder.DishsRecycler.setAdapter(DishsRecyclerAdapter);
        holder.DishsRecycler.setRecycledViewPool(viewPool);
    }


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

    static class ViewHolder extends RecyclerView.ViewHolder implements DishRecyclerAdapter.OnDishRecyclerListener
        private OnRecipeRecyclerListener onRecipeRecyclerListener;
        private Context context;

        TextView RecipeName, RecipeDate;
        ImageView addDish;

        //The Dishs Recycler
        RecyclerView DishsRecycler;

        public ViewHolder(@NonNull View itemView, OnRecipeRecyclerListener onRecipeRecyclerListener, Context context)
        {
            super(itemView);

            this.onRecipeRecyclerListener = onRecipeRecyclerListener;
            this.context = context;

            RecipeName = itemView.findViewById(R.id.RecipeName);
            RecipeDate = itemView.findViewById(R.id.RecipeDate);           
            addDish = itemView.findViewById(R.id.addDish);

            DishsRecycler = itemView.findViewById(R.id.DishsRecyclerView);

            loadListeners(itemView);
        }

        private void loadListeners(@NonNull View initView)
        {
            RecipeName.setOnClickListener(v ->
            {
                PopupMenu popup = new PopupMenu(context, v);
                MenuInflater inflater = popup.getMenuInflater();
                inflater.inflate(R.menu.Recipe_floating_menu, popup.getMenu());
                popup.show();

                popup.setOnMenuItemClickListener(item ->
                {
                    switch (item.getItemId())
                    {
                        case R.id.menuDeleteRecipe:
                            onRecipeRecyclerListener.deleteRecipe(getAdapterPosition());

                            return true;
                        case R.id.menuRenameRecipe:
                            onRecipeRecyclerListener.renameRecipe(getAdapterPosition());

                            return true;
                        case R.id.menuRecipeProps:
                            onRecipeRecyclerListener.RecipeProps(getAdapterPosition());

                            return true;
                        default:
                            return false;
                    }
                });
            });

            addDish.setOnClickListener(v ->
            {
                onRecipeRecyclerListener.addDish(getAdapterPosition());
            });        

        }       


        //******************************* OnDishRecyclerListener *******************************

        @Override
        public void renameDish(int position)
        {
            onRecipeRecyclerListener.renameDish(position, getAdapterPosition());
        }

        @Override
        public void deleteDish(int position)
        {
            onRecipeRecyclerListener.deleteDish(position, getAdapterPosition());
        }
    }
}

儿童(内部)RecyclerView

public class DishRecyclerAdapter extends RecyclerView.Adapter<DishRecyclerAdapter.ViewHolder>
{
    public interface OnDishRecyclerListener
    {
        void renameDish(int position);

        void deleteDish(int position);
    }

    private OnDishRecyclerListener onDishRecyclerListener;

    private ArrayList<Dish> allDishs;
    private Context context;

    public DishRecyclerAdapter(ArrayList<Dish> allDishs, OnDishRecyclerListener onDishRecyclerListener, Context context)
    {
        this.onDishRecyclerListener = onDishRecyclerListener;
        this.allDishs = allDishs;
        this.context = context;
    }

    @NonNull
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType)
    {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.card_Dishs, parent, false);

        return new ViewHolder(context, view, onDishRecyclerListener);
    }

    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position)
    {
        Dish Dish = allDishs.get(position);

        holder.DishName.setText(Dish.getDishName());
    }


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

    public class ViewHolder extends RecyclerView.ViewHolder
    {
        private Context context;      
        TextView DishName; //plus a bunch of other Views I just removed for the sake of simplicity  

        OnDishRecyclerListener onDishRecyclerListener;

        public ViewHolder(Context context, @NonNull View itemView, OnDishRecyclerListener onDishRecyclerListener)
        {
            super(itemView);
            this.context = context;

            DishName = itemView.findViewById(R.id.DishName);

            this.onDishRecyclerListener = onDishRecyclerListener;

            loadListeners(itemView);
        }

        private void loadListeners(@NonNull View v)
        {
            //Rename an Dish
            DishName.setOnClickListener(view ->
            {
                PopupMenu popup = new PopupMenu(context, v);
                MenuInflater inflater = popup.getMenuInflater();
                inflater.inflate(R.menu.Dish_floating_menu, popup.getMenu());
                popup.show();

                popup.setOnMenuItemClickListener(item ->
                {
                    switch (item.getItemId())
                    {
                        case R.id.menuDeleteDish:
                            onDishRecyclerListener.deleteDish(getAdapterPosition());

                            return true;
                        case R.id.menuRenameDish:
                            onDishRecyclerListener.renameDish(getAdapterPosition());

                            return true;
                        case R.id.menuDishProps:

                            return true;
                        default:
                            return false;
                    }
                });
            });         
        }
    }
}

摘录片段并调用父回收者视图:

   @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
    {
        View view = inflater.inflate(R.layout.fragment_Recipe_panel, container, false);

        recyclerRecipe = view.findViewById(R.id.RecipeRecyclerView);

        SimpleItemAnimator simpleItemAnimator = (SimpleItemAnimator) recyclerRecipe.getItemAnimator();

        if(simpleItemAnimator !=null)
        {
            simpleItemAnimator.setSupportsChangeAnimations(true);
        }

        RecipeAdapter = new RecipeRecyclerAdapter(getContext(), allRecipes);
        RecipeAdapter.setOnRecipeRecyclerListener(this);

        //recyclerRecipe.setHasFixedSize(true);
        recyclerRecipe.setLayoutManager(new LinearLayoutManager(getContext()));
        recyclerRecipe.setAdapter(RecipeAdapter);

        return view;
    }

   public void createRecipe(String RecipeName)
    {
        Recipe Recipe = new Recipe(RecipeName, getContext());
        allRecipes.add(0,Recipe);
        RecipeAdapter.notifyItemInserted(0);
    }

    @Override
    public void deleteRecipe(int RecipePosition)
    {
        allRecipes.remove(RecipePosition);
        RecipeAdapter.notifyItemRemoved(RecipePosition);
    }


    @Override
    public void addDish(int RecipePosition)
    {

      allRecipes.get(RecipePosition).getDishs().add(new Dish(DishName));
      RecipeAdapter.notifyItemChanged(RecipePosition);

    }

    @Override
    public void deleteDish(int DishPosition, int RecipePosition)
    {
        Recipe Recipe = allRecipes.get(RecipePosition);
        Dish Dish = Recipe.getDishs().get(DishPosition);

        Dish.getTimer().destroyTimer();
        Recipe.getDishs().remove(DishPosition);
        RecipeAdapter.notifyItemChanged(RecipePosition);
    }
java android android-recyclerview nestedrecyclerview
1个回答
0
投票

我找出了问题所在(经过数小时的努力)。我需要先按顺序通知父回收者,然后通知子回收者。

//adding an item to the inner list
recipeAdapter.notifyItemChanged(recipePosition);            
dishsRecycler.getAdapter().notifyItemInserted(recipe.getDishs().size()-1); 

//deleting an inner list item
recipeAdapter.notifyItemChanged(recipePosition);            
dishsRecycler.getAdapter().notifyItemRemoved()

然而,最大的罪魁祸首是所有内部recyclerviews都有一个公共的recyclerPool,因此从代码中删除了这一行

//REMOVED THESE LINES
private RecyclerView.RecycledViewPool viewPool = new RecyclerView.RecycledViewPool();
holder.DishsRecycler.setRecycledViewPool(viewPool);

此外,由于某种原因,我避免使用notifyDataSet()引发NO_POSITION(-1)。

© www.soinside.com 2019 - 2024. All rights reserved.