简体   繁体   English

当列表足够滚动时,Recycler View适配器无法正常工作

[英]Recycler View adapter not working properly when the list is big enough to scroll

I have a recycler view adapter like the code I provided. 我有一个回收者视图适配器,就像我提供的代码一样。 Everything works fine with the action bar delete function until the list is big enough to scroll. 使用动作栏删除功能,一切正常,直到列表足够滚动为止。

When the list is big selecting multiple items and tapping delete is not deleting the exact selected items. 如果列表很大,则选择多个项目,然后点按“删除”不会删除确切的所选项目。 Its deleting some other items. 它删除了其他一些项目。 But like always after deleting when the list is doesn't need scroll no more its deleting exact selected items. 但是,就像在删除列表之后始终执行删除操作一样,不再需要滚动,它不再删除确切选择的项目。

So what am I doing wrong here? 那我在做什么错呢?

package com.itsred1.a1wallet;

import android.content.Context;
import android.graphics.Color;
import android.support.annotation.NonNull;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.view.ActionMode;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import java.util.ArrayList;

public class RVDirLisAda extends RecyclerView.Adapter<RVDirLisAda.MyViewHolder> {
    private final Context m_con;
    private final LayoutInflater lay_inf;
    private final ArrayList<RVDat> arr_lis_his_dat;
    private ArrayList<Integer> sel_pos_lis = new ArrayList<>();
    private boolean mul_sel;

   RVDirLisAda(Context context, ArrayList<RVDat> his_dat_arr_lis) {
        m_con = context;
        lay_inf = LayoutInflater.from(context);
        this.arr_lis_his_dat = his_dat_arr_lis;
    }

    private ActionMode.Callback act_mod_cal_bac = new ActionMode.Callback() {

        @Override
        public boolean onCreateActionMode(ActionMode mode, Menu menu) {
            mul_sel = true;
            menu.add("Delete");
            return true;
        }

        @Override
        public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
            return false;
        }

        @Override
        public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
            for (int pos : sel_pos_lis) {
                arr_lis_his_dat.remove(pos);
            }
            mode.finish();
            return true;
        }

        @Override
        public void onDestroyActionMode(ActionMode mode) {
            mul_sel = false;
            sel_pos_lis.clear();
            notifyDataSetChanged();
        }
    };

    @NonNull
    @Override
    public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View vie = lay_inf.inflate(R.layout.rv_dir_lis, parent, false);
        return new MyViewHolder(vie);
    }

    @Override
    public void onBindViewHolder(@NonNull final MyViewHolder holder, int position) {
        holder.ini_row(position);
    }

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

    class MyViewHolder extends RecyclerView.ViewHolder {
        private final TextView tv_fil_nam;

        MyViewHolder(View itemView) {
            super(itemView);
            tv_fil_nam = itemView.findViewById(R.id.tv_fil_nam);
        }

        void ini_row(final int pos){
            if (sel_pos_lis.contains(pos)){
                tv_fil_nam.setBackgroundColor(Color.LTGRAY);
            } else {
                tv_fil_nam.setBackgroundColor(Color.WHITE);
            }

            final String fil_nam = arr_lis_his_dat.get(pos).get_row1_col2();
            final String tra_typ = arr_lis_his_dat.get(pos).get_tra_typ();
            final String id = arr_lis_his_dat.get(pos).get_row2_col1();
            tv_fil_nam.setText(fil_nam);
            if(tra_typ.equals("folder")) {
                tv_fil_nam.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ico_fol, 0, 0, 0);
            } else if (tra_typ.equals("file")) {
                tv_fil_nam.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ico_db,0,0,0);
            }

            tv_fil_nam.setOnLongClickListener(new View.OnLongClickListener() {
                @Override
                public boolean onLongClick(View v) {
                    if(!mul_sel){
                        ((AppCompatActivity) v.getContext()).startSupportActionMode(act_mod_cal_bac);
                    }
                    sel_row(pos);
                    return true;
                }
            });

           tv_fil_nam.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    if(mul_sel){
                        sel_row(pos);
                    } else {
                        cal_bac(id, fil_nam, pos);
                    }
                }
            });
        }

        void sel_row(int pos) {
            if (mul_sel) {
                if (sel_pos_lis.contains(pos)) {
                    int i = sel_pos_lis.lastIndexOf(pos);
                    sel_pos_lis.remove(i);
                    tv_fil_nam.setBackgroundColor(Color.WHITE);
                } else {
                    sel_pos_lis.add(pos);
                    tv_fil_nam.setBackgroundColor(Color.LTGRAY);
                }
            }
        }

        void cal_bac(String id, String tra_typ, int pos) {
            CalBacCom cal_bac_com = null;
            if (m_con instanceof CalBacCom) {
                cal_bac_com = (CalBacCom) m_con;
            }

            if (cal_bac_com != null) {
                cal_bac_com.ini_cal_bac (id, tra_typ, pos, "row_cli");
            }
        }

    }
}

Inside your OnClickListener s you are referencing a position value that could change very quickly as you scroll up or down. 在您的OnClickListener内部,您引用的位置值可能会随着上下滚动而快速变化。 This happens because your view holder is re-used to inflate new items that become visible thus avoiding new memory allocation, in the other words, the adapter takes the view holder from items that become "hidden" and reuse them on items that become "visible" while you scroll. 发生这种情况是因为您的视图持有人被重新使用,以使可见的新项目膨胀,从而避免了新的内存分配,换句话说,适配器从“隐藏”的项目中获取视图持有人,然后在“可见”的项目上重复使用它们滚动时。 Instead use the getAdapterPosition method inside those listeners. 而是在这些侦听器中使用getAdapterPosition方法。 For example, instead of doing this... 例如,不要这样做...

tv_fil_nam.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if(mul_sel){
                    sel_row(pos);
                } else {
                    cal_bac(id, fil_nam, pos);
                }
            }
        });

do this... 做这个...

tv_fil_nam.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if(mul_sel){
                    sel_row(getAdapterPosition());
                } else {
                    cal_bac(id, fil_nam, getAdapterPosition());
                }
            }
        });
for (int pos : sel_pos_lis) {
    arr_lis_his_dat.remove(pos);
}

This part of your code has an issue, when you remove some item at some position then the position of next items will change and other remove actions could fail and remove some other items. 代码的此部分存在问题,当您在某个位置删除某些项目时,下一个项目的位置将发生变化,其他删除操作可能会失败并删除其他一些项目。 You should remove options with a higher index first but it's not related to scrolling and big lists. 您应该先删除索引较高的选项,但这与滚动和大列表无关。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM