首页 > 解决方案 > 嵌套的回收器适配器项目进入错误的回收器视图

问题描述

在我的应用程序上,我有一个 Recyler View,里面有多个回收站视图。内部回收器视图是动态插入的。我遇到的问题是,来自某些内部回收站视图的某些项目将转到其他不应该有项目的内部回收站视图,如下图所示。

回收商意见

顶部回收站视图不应该有这些项目,而底部是正确的。我注意到这些项目总是在同一个回收站视图上出现故障,调试后我还注意到在出现故障的视图上,它甚至没有进入子适配器,这使得它更加奇怪。

我还应该提到,子回收器视图是根据 volley 请求插入的。我向 API 发出请求,它会生成项目。我也检查过,API 给出了正确的响应。

片段代码(调用主回收器视图的地方):

RequestQueue requestQueue;
    String URL;

    RecyclerView catList;
    CategoriesMainRecycleAdapter adapter;
    List<String> cats;

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

        catList = v.findViewById(R.id.crv_main_categories);
        cats = new ArrayList<>();
        URL = /*Removed this part for privacy reasons*/;
        Submit();

        // Inflate the layout for this fragment
        return v;
    }

    private void Submit()
    {
        requestQueue = Volley.newRequestQueue(getActivity());
        StringRequest stringRequest = new StringRequest(Request.Method.GET, URL, new Response.Listener<String>() {
            @Override
            public void onResponse(String response) {
                try {
                    JSONArray jsonArray = new JSONArray(response);

                    for (int i = 0; i < jsonArray.length(); i++)
                    {
                        JSONObject cat = jsonArray.getJSONObject(i);

                        String a;
                        a = cat.getString("mCategoryName");
                        cats.add(a);
                    }

                    if (getActivity()!=null) {
                        adapter = new CategoriesMainRecycleAdapter(getActivity(), cats, (String) getText(R.string.website_link));
                        catList.setLayoutManager(new LinearLayoutManager(getActivity()));
                        catList.setAdapter(adapter);
                    }

                } catch (JSONException e) {
                    Toast.makeText(getContext(), R.string.login_communication_error, Toast.LENGTH_LONG).show();
                    e.printStackTrace();
                }
            }
        }, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                Toast.makeText(getActivity(), R.string.login_communication_error, Toast.LENGTH_SHORT).show();
                error.printStackTrace();
            }
        });
        requestQueue.add(stringRequest);
    }

主回收器适配器代码(这是调用子适配器的地方):

@Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
        holder.title.setText(capitalizeLetters(mCats.get(position)));
        holder.viewAll.setImageResource(R.drawable.ic_baseline_arrow_forward_24_black);

        holder.lbl_error.setText(R.string.no_anime_with_category_error);
        holder.lbl_error.setVisibility(View.INVISIBLE);

        holder.viewAll.setOnClickListener(
                new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        v.startAnimation(AnimationUtils.loadAnimation(mContext, R.anim.image_click));

                        Intent i = new Intent(mContext, anime_category.class);
                        i.putExtra("Category", mCats.get(position));
                        mContext.startActivity(i);
                    }
                }
        );

        //Start the other recycler views
        URL = /*Removed for privacy reasons*/;

        String data = "{"+
                "\"mCategoryName\":" + "\"" + mCats.get(position) + "\"" +
                "}";

        Submit(data, holder);

    }

    private void Submit(String data, ViewHolder holder)
    {
        final String savedata= data;

        requestQueue = Volley.newRequestQueue(Objects.requireNonNull(mContext));
        StringRequest stringRequest = new StringRequest(Request.Method.POST, URL, new Response.Listener<String>() {
            @Override
            public void onResponse(String response) {
                try {
                    holder.lbl_error.setVisibility(View.INVISIBLE);
                    List<anime_class> animes = new ArrayList<>();
                    JSONArray jsonArray = new JSONArray(response);

                    for (int i = 0; i < jsonArray.length(); i++)
                    {
                        JSONObject anime = jsonArray.getJSONObject(i);

                        anime_class a = new anime_class();
                        a.setmNameEN(anime.getString("mNameEN"));
                        a.setmNameJP(anime.getString("mNameJP"));
                        a.setmDescription(anime.getString("mDescription"));
                        a.setmThumbnail(anime.getString("mThumbnail"));
                        a.setmEpisodeCount(anime.getInt("mEpisodeCount"));
                        a.setmOnGoing(anime.getBoolean("mOnGoing"));

                        //Add Categories
                        List<String> cats = new ArrayList<>();
                        JSONArray catArray = anime.getJSONArray("mCategories");
                        for (int i2 = 0; i2 < catArray.length(); i2++)
                        {
                            cats.add(catArray.get(i2).toString());
                        }
                        a.setmCategories(cats);
                        animes.add(a);
                    }
                    if (mContext!=null) {
                        LinearLayoutManager linearLayoutManager = new LinearLayoutManager(
                                holder.rcv.getContext(),
                                LinearLayoutManager.HORIZONTAL,
                                false
                        );
                        linearLayoutManager.setInitialPrefetchItemCount(animes.size());
                        CategoriesSubRecycleAdapter adapter = new CategoriesSubRecycleAdapter(mContext, animes);
                        holder.rcv.setLayoutManager(linearLayoutManager);
                        holder.rcv.setAdapter(adapter);
                        holder.rcv.setRecycledViewPool(catAnime);
                    }
                } catch (JSONException e) {
                    Toast.makeText(mContext, R.string.login_communication_error, Toast.LENGTH_LONG).show();
                    e.printStackTrace();

                }
            }
        }, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                if(error.networkResponse.statusCode == 404)
                {
                    holder.lbl_error.setVisibility(View.VISIBLE);
                }
                else
                    Toast.makeText(mContext, R.string.login_communication_error, Toast.LENGTH_SHORT).show();
                error.printStackTrace();
            }
        }) {
            @Override
            public String getBodyContentType() {
                return "application/json; charset=utf-8";
            }

            @Override
            public byte[] getBody() throws AuthFailureError {
                return savedata == null ? null : savedata.getBytes(StandardCharsets.UTF_8);
            }

        };
        requestQueue.add(stringRequest);
    }

子回收器适配器(根据我所做的一些调试,这部分似乎工作正常):

 @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
        holder.title.setText(capitalizeLetters(mAnime.get(position).getmNameEN()));
        Glide.with(mContext).load(mAnime.get(position).getmThumbnail()).into(holder.thumbnail);

        holder.crv_.setOnClickListener(
                new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        Intent i = new Intent(mContext, anime_page.class);
                        i.putExtra("mNameEN", mAnime.get(position).getmNameEN());
                        i.putExtra("mThumbnail", mAnime.get(position).getmThumbnail());
                        mContext.startActivity(i);
                    }
                }
        );
    }

标签: androidandroid-studioandroid-layoutandroid-recyclerview

解决方案


我找到了解决问题的技巧,但我不相信它非常优化。在 Main Recycler Adapter 上,当我调用 Submit 方法从请求中获取数据时,在 onErrorResponse 上,我通过创建一个空 List 并将其提供给适配器来添加 0 个项目。

            @Override
            public void onErrorResponse(VolleyError error) {
                if(error.networkResponse.statusCode == 404)
                {
                    List<anime_class> animes = new ArrayList<>();

                    LinearLayoutManager linearLayoutManager = new LinearLayoutManager(
                            holder.rcv.getContext(),
                            LinearLayoutManager.HORIZONTAL,
                            false
                    );
                    
                    linearLayoutManager.setInitialPrefetchItemCount(animes.size());
                    CategoriesSubRecycleAdapter adapter = new CategoriesSubRecycleAdapter(mContext, animes);

                    holder.rcv.setLayoutManager(linearLayoutManager);

                    holder.rcv.setAdapter(adapter);
                    holder.rcv.getRecycledViewPool().clear();
                    holder.rcv.setRecycledViewPool(catAnime);
                    holder.rcv.setNestedScrollingEnabled(false);
                    adapter.notifyDataSetChanged();
                    holder.lbl_error.setVisibility(View.VISIBLE);
                }
                else
                    Toast.makeText(mContext, R.string.login_communication_error, Toast.LENGTH_SHORT).show();
                error.printStackTrace();

推荐阅读