过滤 RecyclerView 项目并单击它后会给出错误的项目

Posted

技术标签:

【中文标题】过滤 RecyclerView 项目并单击它后会给出错误的项目【英文标题】:After Filter a RecyclerView item and clicking it gives wrong item 【发布时间】:2021-04-28 17:56:29 【问题描述】:

对通过 json 获取的 Recyclerview 项目执行过滤后。当我在过滤列表后单击时,它打开了错误的项目。假设 A、B、C、D 在我的列表中,当我过滤 B 并单击它时 - 它显示了错误的项目(例如:A、C、D)而不是 B。如何解决这个问题?

MainActivity.java:

public class exit_Activity extends AppCompatActivity implements MyAdapter.OnItemClickListener 
    String Show_url = "https://retrieve.php";
    public static final String EXTRA_ID = "id";
    public static final String EXTRA_V = "v";
    public static final String EXTRA_Name = "name";
    public static final String EXTRA_t = "in";
    public static final String EXTRA_o = "out";
    public static final String EXTRA_date = "date";
    public static final String EXTRA_yes = "yes";

    RecyclerView removeView;
    private AlertDialog alertDialog;
    ProgressBar progressBar;
    NetworkChangeListerner networkChangeListerner = new NetworkChangeListerner();
    private SwipeRefreshLayout mSwipeRefreshLayout;
    private ArrayList<Employee> mEmployeeList;
    private MyAdapter myadapter;
    TextInputEditText search;

    @Override
    protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_exit_);
        retrieveData();
        Toolbar toolbar = findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        ///
        mSwipeRefreshLayout = (SwipeRefreshLayout) findViewById(R.id.refreshlayout);
        mSwipeRefreshLayout.setColorSchemeResources(R.color.black, R.color.green, R.color.red);
       

        progressBar = (ProgressBar) findViewById(R.id.progressbar);
        Sprite FoldingCube = new Wave();
        progressBar.setIndeterminateDrawable(FoldingCube);
      
        //
        search = findViewById(R.id.search);
        //exit
        removeView = findViewById(R.id.exit_entry);
        removeView.setHasFixedSize(true);
        removeView.setLayoutManager(new LinearLayoutManager(this));
        mEmployeeList = new ArrayList<>();

        myadapter = new MyAdapter(exit_Activity.this, mEmployeeList);
        removeView.setAdapter(myadapter);

        //end


        search.addTextChangedListener(new TextWatcher() 
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) 
            

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) 
            

            @Override
            public void afterTextChanged(Editable s) 
                filter(s.toString());
            
        );
    

    private void filter(String text) 
        ArrayList<Employee> filteredList = new ArrayList<>();
        for (Employee item : mEmployeeList) 
            if (item.getVehicle_number().toLowerCase().contains(text.toLowerCase())) 
                filteredList.add(item);
            
        
       myadapter.filterList(filteredList);
    


    public void retrieveData() 
        StringRequest request = new StringRequest(Request.Method.POST, Show_url,
                new Response.Listener<String>() 
                    @Override
                    public void onResponse(String response) 
                        mEmployeeList.clear();
                        try 

                            JSONObject jsonObject = new JSONObject(response);
                            String sucess = jsonObject.getString("success");

                            JSONArray jsonArray = jsonObject.getJSONArray("user_data");

                            if (sucess.equals("1")) 

                                for (int i = 0; i < jsonArray.length(); i++) 

                                    JSONObject object = jsonArray.getJSONObject(i);
                                    String id = object.getString("id");
                                    String vehicle_number = object.getString("number");
                                    String driver_name = object.getString("name");
                                    String entry_time = object.getString("time");
                                    String entry_date = object.getString("date");
                                    String exit_time = object.getString("ttime");
                                    String yes = object.getString("yes");
                                    mEmployeeList.add(new Employee(id, number, name, time, date, ttime, yes));
                                
                               myadapter.notifyDataSetChanged();
                              myadapter.setOnItemClickListener(exit_Activity.this);
                                progressBar.setVisibility(View.GONE);
                                mSwipeRefreshLayout.setRefreshing(false);
                                Toast.makeText(getApplicationContext(), "List Updated", Toast.LENGTH_SHORT).show();
                            


                         catch (JSONException e) 
                            e.printStackTrace();
                        


                    

                , new Response.ErrorListener() 
            @Override
            public void onErrorResponse(VolleyError error) 
                Toast.makeText(exit_Activity.this, error.getMessage(), Toast.LENGTH_LONG).show();
                error.printStackTrace();
            
        );
        RequestQueue requestQueue = Volley.newRequestQueue(this);
        requestQueue.add(request);

    

    
    @Override
    public void onItemClick(int position) 
        Intent ediIntent = new Intent(this, Edit_Activity.class);
        Employee clickedItem = mEmployeeList.get(position);
        ediIntent.putExtra(EXTRA_ID, clickedItem.getId());
        ediIntent.putExtra(EXTRA_V, clickedItem.getnumber());
        ediIntent.putExtra(EXTRA_Name, clickedItem.getname());
        ediIntent.putExtra(EXTRA_date, clickedItem.getdate());
        ediIntent.putExtra(EXTRA_t, clickedItem.gettime());
        ediIntent.putExtra(EXTRA_o, clickedItem.getttime());
        ediIntent.putExtra(EXTRA_yes, clickedItem.getYes());
        startActivity(ediIntent);
    

Myadapter.class:

public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder>


    private Context mcontext;
    private ArrayList<Employee> marrayListEmployee;
    private OnItemClickListener mListener;

    public interface OnItemClickListener 
        void onItemClick(int position);
    
    public void setOnItemClickListener(OnItemClickListener listener) 
        mListener = listener;
    
    public MyAdapter(Context context, ArrayList<Employee> arrayListEmployee) 
        mcontext = context;
        marrayListEmployee = arrayListEmployee;
    

  /*  public MyAdapter(@NonNull Context context, List<Employee> arrayListEmployee) 
        super(context, R.layout.custom_list_item,arrayListEmployee);

        this.context = context;
        this.arrayListEmployee = arrayListEmployee;

    
*/
  @Override
  public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) 
      View v = LayoutInflater.from(mcontext).inflate(R.layout.custom_list_item, parent, false);
      MyViewHolder evh = new MyViewHolder(v);
      return evh;

  
    @Override
    public void onBindViewHolder(MyViewHolder holder, int position) 
        Employee currentItem = marrayListEmployee.get(position);
        String tvID = currentItem.getId();
        String tvName = currentItem.getnumber();
        holder.tvID.setText(tvID);
        holder.tvName.setText(tvName);


    
    @Override
    public int getItemCount() 
        return marrayListEmployee.size();
    
    public class MyViewHolder extends RecyclerView.ViewHolder 

        public TextView tvID;
        public TextView tvName;
        public MyViewHolder(View itemView) 
            super(itemView);

            tvID = itemView.findViewById(R.id.txt_id);
            tvName = itemView.findViewById(R.id.number);
            itemView.setOnClickListener(new View.OnClickListener() 
                @Override
                public void onClick(View v) 
                    if (mListener != null) 
                        int position = getAdapterPosition();
                        if (position != RecyclerView.NO_POSITION) 
                            mListener.onItemClick(position);

                        
                    
                
            );
        
    
 
   public void filterList(ArrayList<Employee> filteredList) 
       marrayListEmployee = filteredList;
       notifyDataSetChanged();
   

【问题讨论】:

【参考方案1】:

您必须从过滤后更改的列表中获取元素,而不是旧列表

private ArrayList<Employee> filteredList = new ArrayList<Employee>();
private void filter(String text) 
  filteredList.clear();
  for (Employee item : mEmployeeList) 
    if (item.getVehicle_number().toLowerCase().contains(text.toLowerCase())) 
      filteredList.add(item);
    
  
  myadapter.filterList(filteredList);


@Override
public void onItemClick(int position) 
  Intent ediIntent = new Intent(this, Edit_Activity.class);
  if(filteredList.size() > 0) 
    Employee clickedItem = filteredList.get(position);
    else 
      Employee clickedItem = mEmployeeList.get(position);
   
  ...

【讨论】:

你的filter函数里面是ArrayList filteredList,转换成字段使用 1.它在 afterTextChanged... 之后重复项目... 2. 当我从 mEmployeeList 中选择项目时应用程序崩溃,日志:java.lang.IndexOutOfBoundsException: Index: 2, Size: 0 at java.util.ArrayList.get(ArrayList.java:437)在 com.peeyusquad.vee.exit_Activity.onItemClick(exit_Activity.java:310) 在 com.peeyusquad.vee.MyAdapter$MyViewHolder$1.onClick(MyAdapter.java:84) 在 android.view.View.performClick(View.java:第7300章) 重复问题已解决,但当我单击带有日志的未过滤列表中的项目时应用程序崩溃:java.lang.IndexOutOfBoundsException:索引:1,大小:0 在 java.util.ArrayList。 get(ArrayList.java:437) at com.peeyusquad.vee.exit_Activity.onItemClick(exit_Activity.java:312) at com.peeyusquad.vee.MyAdapter$MyViewHolder$1.onClick(MyAdapter.java:84) at android.view。 View.performClick(View.java:7300) at android.view.View.performClickInternal(View.java:7277) at android.view.View.access$3600(View.java:822)【参考方案2】:

已编辑

抱歉,我没有看到标记的正确答案...

我不会删除,用这个来改进一些东西

不要复制/粘贴代码,因为它没有经过测试,尝试了解更改

在过滤器方法中,您将 marrayListEmployee 替换为过滤列表,而在 retrieveData 方法中,您没有设置任何内容,只是通知了适配器

适配器

public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder>

    private Context mcontext;
    private ArrayList<Employee> marrayListEmployee;
    private OnItemClickListener mListener;

    public interface OnItemClickListener 
        void onItemClick(int position);
    
    public void setOnItemClickListener(OnItemClickListener listener) 
        mListener = listener;
    
    public MyAdapter(Context context, ArrayList<Employee> arrayListEmployee) 
        mcontext = context;
        marrayListEmployee = arrayListEmployee;
    

    @Override
    public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) 
        View v = LayoutInflater.from(mcontext).inflate(R.layout.custom_list_item, parent, false);
        return new MyViewHolder(v);

    
    @Override
    public void onBindViewHolder(MyViewHolder holder, int position) 
        Employee currentItem = marrayListEmployee.get(position);
        holder.tvID.setText(currentItem.getId());
        holder.tvName.setText(currentItem.getnumber());

        //TODO set setOnClickListener here instead in ViewHolder constructor
        holder.itemView.setOnClickListener(new View.OnClickListener() 
            @Override
            public void onClick(View v) 
                if (mListener != null) 
                    int position = holder.getAdapterPosition();
                    if (position != RecyclerView.NO_POSITION) 
                        mListener.onItemClick(position);

                    
                
            
        );
    


    @Override
    public int getItemCount() 
        return marrayListEmployee.size();
    


    public void filterList(ArrayList<Employee> filteredList) 
        marrayListEmployee = filteredList;
        notifyDataSetChanged();
    




    public class MyViewHolder extends RecyclerView.ViewHolder 

        public TextView tvID;
        public TextView tvName;

        public MyViewHolder(View itemView) 
            super(itemView);
            tvID = itemView.findViewById(R.id.txt_id);
            tvName = itemView.findViewById(R.id.number);
        
    

Activity - onCreate

@Override
    protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
         
        ......

        removeView = findViewById(R.id.exit_entry);
        removeView.setHasFixedSize(true);
        removeView.setLayoutManager(new LinearLayoutManager(this));
        mEmployeeList = new ArrayList<>(); 
        removeView.setAdapter(new MyAdapter(this, mEmployeeList));
        myadapter.setOnItemClickListener(this); //TODO set click listener here instead evrytime in retrieveData method
         
        .........
 
    

RetrieveData 数据方法

public void retrieveData() 
        StringRequest request = new StringRequest(Request.Method.POST, Show_url,
                new Response.Listener<String>() 
                    @Override
                    public void onResponse(String response) 
                        mEmployeeList.clear();
                        try 

                            JSONObject jsonObject = new JSONObject(response);
                            String sucess = jsonObject.getString("success");

                            JSONArray jsonArray = jsonObject.getJSONArray("user_data");

                            if (sucess != null && sucess.equals("1"))  //check null

                                for (int i = 0; i < jsonArray.length(); i++) 

                                    JSONObject object = jsonArray.getJSONObject(i);
                                    String id = object.getString("id");
                                    String vehicle_number = object.getString("number");
                                    String driver_name = object.getString("name");
                                    String entry_time = object.getString("time");
                                    String entry_date = object.getString("date");
                                    String exit_time = object.getString("ttime");
                                    String yes = object.getString("yes");
                                    mEmployeeList.add(new Employee(id, number, name, time, date, ttime, yes));
                                
                                //myadapter.notifyDataSetChanged(); // remove this,
                                //myadapter.setOnItemClickListener(exit_Activity.this); remove this, set it in onCreate method
                                //TODO you have to reset mEmployeeList (below) because you changed it by filtering
                                myadapter.filterList(mEmployeeList); // change method name to swapData()
                                progressBar.setVisibility(View.GONE);
                                mSwipeRefreshLayout.setRefreshing(false);
                                Toast.makeText(getApplicationContext(), "List Updated", Toast.LENGTH_SHORT).show();
                            


                         catch (JSONException e) 
                            e.printStackTrace();
                        


                    

                , new Response.ErrorListener() 
            @Override
            public void onErrorResponse(VolleyError error) 
                Toast.makeText(exit_Activity.this, error.getMessage(), Toast.LENGTH_LONG).show();
                error.printStackTrace();
            
        );
        RequestQueue requestQueue = Volley.newRequestQueue(this);
        requestQueue.add(request);

    

过滤方法

private void filter(String text) 
        if(text == null || text.isEmpty()) return;
        ArrayList<Employee> filteredList = new ArrayList<>();
        for (Employee item : mEmployeeList) 
            if (item.getVehicle_number() == null) continue; // TODO check null
            if (item.getVehicle_number().toLowerCase().contains(text.toLowerCase())) 
                filteredList.add(item);
            
        
        myadapter.filterList(filteredList); // change method name to swapData()
    

【讨论】:

谢谢,先生,您来了&回答..但在无法解决方法时出错('int position = getAdapterPosition();') 对不起,改一下:holder.getAdapterPosition()

以上是关于过滤 RecyclerView 项目并单击它后会给出错误的项目的主要内容,如果未能解决你的问题,请参考以下文章

在Android recyclerVIew中单击项目时如何保存状态

从片段中获取意图值后,我如何在 recyclerview 项目中实现单击

单击 Recyclerview 中的项目后,OnItem 单击无法正常工作

单击后退按钮时,在 RecyclerView 中获得相同的项目位置

可过滤在 Recyclerview 中无法按预期工作

如何从recyclerview适配器获取选定项目的数量?