Listview自定义过滤器在过滤列表中单击错误的项目

Posted

技术标签:

【中文标题】Listview自定义过滤器在过滤列表中单击错误的项目【英文标题】:Listview custom filter gives wrong item on-clicked in filtered list 【发布时间】:2021-04-27 10:29:50 【问题描述】:

当我过滤我的列表并单击列表视图中的一个项目时,它会提供错误的项目信息。 假设我的列表包含 X、Y、Z。当我在列表中搜索以 Y 开头的内容时,我会得到 Y,但是当我单击 Y 时,它会返回 X 或任何随机项目数据。 我的主要活动:

public class exit_Activity extends AppCompatActivity 
    String Show_url = "https://retrieve.php";
    ListView removeView;
    MyAdapter adapter;
    public static ArrayList<Employee> employeeArrayList = new ArrayList<>();
    Employee employee;
   ProgressBar progressBar;
    private SwipeRefreshLayout mSwipeRefreshLayout;
    public static ArrayList<Employee> filterList = new ArrayList<>();
    EditText 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);
        mSwipeRefreshLayout.setProgressBackgroundColorSchemeColor(getResources().getColor(R.color.main_blue));
        mSwipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() 
            @Override
            public void onRefresh() 
                mSwipeRefreshLayout.setRefreshing(true);
                Toast.makeText(getApplicationContext(), "Updating..", Toast.LENGTH_SHORT).show();
                retrieveData();
                // do nothing
            
        );

        progressBar = (ProgressBar) findViewById(R.id.progressbar);
        Sprite FoldingCube = new Wave();
        progressBar.setIndeterminateDrawable(FoldingCube);
        //time and date
        final Handler handler = new Handler();
        handler.postDelayed(new Runnable() 
            @Override
            public void run() 
                exit_time();
                removeView.requestLayout();
                handler.postDelayed(this, 500);
            
        , 500);
        //
      
        //
        //exit
        removeView = findViewById(R.id.exit_entry);
        adapter = new MyAdapter(this, employeeArrayList);
        removeView.setAdapter(adapter);
        //end
        removeView.setOnItemClickListener(new AdapterView.OnItemClickListener() 
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) 

                ProgressDialog progressDialog = new ProgressDialog(view.getContext());
                startActivity(new Intent(getApplicationContext(), Edit_Activity.class)
                        .putExtra("id", id));
                finish();
            
        );
//searchView
        search = findViewById(R.id.search);
        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) 
                filterList.clear();
                if (s.toString().isEmpty()) 
                    removeView.setAdapter(new MyAdapter(getApplicationContext(), employeeArrayList));
                    adapter.notifyDataSetChanged();
                 else 
                    Filter(s.toString());
                
            
        );
        //end


    

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

                        employeeArrayList.clear();
                        try 

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

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

                            if (sucess.equals("1")) 

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

                                    JSONObject object = jsonArray.getJSONObject(i);
                                    String id = object.getString("id");
                                    String number = object.getString("number");
                                    String name = object.getString("name");
                                    String time = object.getString("surnam");
                                    String date = object.getString("dob");
                                    String time = object.getString("die");
                                    String yes = object.getString("yes");
                                    employee = new Employee(id, number, name, time, date, time, yes);
                                    employeeArrayList.add(employee);
                                    adapter.notifyDataSetChanged();
                                

                                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) 
        for (Employee post : employeeArrayList) 
            String filterPattern = text.toLowerCase().trim();
            if (post.getnumber().toLowerCase().contains(filterPattern)) 
                filterList.add(post);
            
        
        removeView.setAdapter(new MyAdapter(getApplicationContext(), filterList));
        adapter.notifyDataSetChanged();
    

MyAdapter.class:

public class MyAdapter extends ArrayAdapter<Employee> implements Filterable

    Context context;
    List<Employee> arrayListEmployee;


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

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

    

    @NonNull
    @Override
    public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) 

        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.custom_list_item,null,true);

        TextView tvID = view.findViewById(R.id.txt_id);
        TextView tvName = view.findViewById(R.id.view_vehicle_number);

        tvID.setText(arrayListEmployee.get(position).getId());
        tvName.setText(arrayListEmployee.get(position).getnumber());

        return view;
    
    @Override
    public int getCount() 
        return super.getCount();
    

请用简单的语言解释并提供我的解决方案。我是安卓工作室的新手。提前谢谢x1000

【问题讨论】:

【参考方案1】:

我发现方法有问题(检查 cmets):

private void Filter(String text) 
        for (Employee post : employeeArrayList) 
            String filterPattern = text.toLowerCase().trim();
            if (post.getnumber().toLowerCase().contains(filterPattern)) 
                filterList.add(post);
            
         
        //below every time you create new instance of MyAdapter - try comment this line (below) and test it 
        removeView.setAdapter(new MyAdapter(getApplicationContext(), filterList));
        //this is your first instance but you set new adapter for listView
        adapter.notifyDataSetChanged();
     

并用这个替换你的方法:

private void Filter(String text) 
        for (Employee post : employeeArrayList) 
            String filterPattern = text.toLowerCase().trim();
            if (post.getnumber().toLowerCase().contains(filterPattern)) 
                filterList.add(post);
            
        
        adapter.clear()
        adapter.addAll(filterList);
    

所以你不用每次都创建适配器的新实例,只需交换现有适配器的数据

我尚未对其进行测试,但它应该可以与 OnItemClickListener 一起正常工作...

已编辑

同样的问题……

@Override
    public void afterTextChanged(Editable s) 
        filterList.clear();
        if (s.toString().isEmpty()) 
            //you set new instance of adapter and notify old, try comment this line (below) and test it 
            //removeView.setAdapter(new MyAdapter(getApplicationContext(), employeeArrayList)); 
            adapter.notifyDataSetChanged();
         else 
            Filter(s.toString());
        
    

      

改成这个

        @Override
        public void afterTextChanged(Editable s) 
            if (!s.toString().isEmpty()) 
                 filterList.clear(); //TODO here is problem, move this to your filter method
                 Filter(s.toString());
             else 
               //Do nothing, if the EditText field is empty the list will remain filled
            
        

还有其他方法可以解决和改进,但我不想让你感到困惑,因为 android 对你来说是全新的体验

已编辑

您使用的是 ArrayAdapter,但我认为它是 RecyclerView,忘记 swapData 方法并尝试新的更改...抱歉

adapter.clear()
adapter.addAll(filterList);

【讨论】:

public void swapData(List> newItems) if (newItems != null) this.arrayListEmployee = newItems; notifyDataSetChanged(); >>>>>>>>>>>>>> 这里 public void swapData(List> newItems) 显示错误,将 List 转换为 并在该应用程序崩溃后 只需更改 public static ArrayList filterList = new ArrayList();到 public static List filterList = new ArrayList() 或 swapData(ArrayList newItems) E/AndroidRuntime:致命异常:主进程:com.peeyusquad.veeta,PID:22503 java.lang.IndexOutOfBoundsException:索引:5,大小:5 在 java.util.ArrayList.get(ArrayList .java:437) 在 com.peeyusquad.veeta.MyAdapter.getView(MyAdapter.java:45) 在 android.widget.AbsListView.obtainView(AbsListView.java:2442) 在 android.widget.ListView.makeAndAddView(ListView.java: 2098) 在 android.widget.ListView.fillDown(ListView.java:813) 你真是太棒了兄弟 但还剩下一个小问题。当 if (s.toString().isEmpty()) 它不返回项目时。 (空白列表视图)

以上是关于Listview自定义过滤器在过滤列表中单击错误的项目的主要内容,如果未能解决你的问题,请参考以下文章

带有过滤器 Android 的自定义 Listview 适配器

ListView 中的自定义过滤 ArrayAdapter

过滤后ListView不更新

如何在 BaseAdapter 中使用 getFilter() 过滤 ListView

自定义 listView 数组,搜索,在 NotifyDataSetChanged 上崩溃,加上 listView 没有得到更新

使用自定义(对象)适配器过滤 ListView