搜索过滤器后如何更新android RecyclerView项目?

Posted

技术标签:

【中文标题】搜索过滤器后如何更新android RecyclerView项目?【英文标题】:How to update android RecyclerView items after search filter? 【发布时间】:2019-08-09 01:51:03 【问题描述】:

我正在尝试使用 android Filterable 类过滤 RecyclerView

我已按照本教程 Android RecyclerView adding Search Filter 完成此任务。

项目运行没有错误,我在日志中显示了结果数组,我得到了正确的结果但是UI没有任何变化。

这是我的适配器代码:

  public class CoffretPicturesAdapter extends RecyclerView.Adapter<CoffretPicturesAdapter.MyViewHolder> implements Filterable 

private Context mContext ;
private ArrayList<Picture> mData ;
private ArrayList<Picture> mDataFiltered;

public CoffretPicturesAdapter(Context mContext, ArrayList<Picture> mData) 
    this.mContext = mContext;
    this.mData = mData;
    this.mDataFiltered = mData;


@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) 
    View view ;
    LayoutInflater mInflater = LayoutInflater.from(mContext);
    view = mInflater.inflate(R.layout.cardview_item_coffret,parent,false);
    return new MyViewHolder(view);


@Override
public Filter getFilter() 
    return new Filter() 
        @Override
        protected FilterResults performFiltering(CharSequence charSequence) 
            String charString = charSequence.toString();
            if (charString.isEmpty()) 
                mDataFiltered = mData;
             else 
                ArrayList<Picture> filteredList = new ArrayList<>();
                for (Picture row : mData) 

                    // name match condition. this might differ depending on your requirement
                    // here we are looking for name or phone number match
                    if (row.getTitle().toLowerCase().contains(charString.toLowerCase())) 
                        filteredList.add(row);
                    
                

                mDataFiltered = filteredList;
            

            FilterResults filterResults = new FilterResults();
            filterResults.values = mDataFiltered;
            return filterResults;
        

        @Override
        protected void publishResults(CharSequence charSequence, FilterResults filterResults) 
            mDataFiltered = (ArrayList<Picture>) filterResults.values;
            notifyDataSetChanged();
        
    ;


@Override
public void onBindViewHolder(MyViewHolder holder, final int position) 
    holder.coffret_title.setText(mData.get(position).getTitle());
    Picasso.with(mContext).load(mData.get(position).getUri()).placeholder(R.drawable.placeholder).resize(500,500).centerCrop().into(holder.coffret_thumbnail);
    holder.cardView.setOnClickListener(new View.OnClickListener() 
        @Override
        public void onClick(View v) 
            Toast.makeText(mContext, "" + mData.get(position).getTitle(), Toast.LENGTH_SHORT).show();
            Intent intent = new Intent(mContext, SelectedPicPreviewActivity.class);
            intent.putExtra("image_url", mData.get(position).getUri().toString());
            mContext.startActivity(intent);

        
    );


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


public static class MyViewHolder extends RecyclerView.ViewHolder 

    TextView coffret_title;
    ImageView coffret_thumbnail;
    LinearLayout cardView ;

    public MyViewHolder(View itemView) 
        super(itemView);

        coffret_title = (TextView) itemView.findViewById(R.id.coffret_title_id) ;
        coffret_thumbnail = (ImageView) itemView.findViewById(R.id.coffret_img_id);
        cardView = (LinearLayout) itemView.findViewById(R.id.cardview_id);

    

这是从我的外部存储中获取数据的功能

  private ArrayList<Picture> getData() 
    ArrayList<Picture> results= new ArrayList<>();
    //TARGET FOLDER
    File picsFolder = new File(Environment.getExternalStorageDirectory() + "/coffretPics");

    Picture s;

    if (picsFolder.exists()) 
        //GET ALL FILES IN DOWNLOAD FOLDER
        File[] files = picsFolder.listFiles();

        //LOOP THRU THOSE FILES GETTING NAME AND URI
        for (int i = files.length - 1; i >= 0; i--) 
            File file = files[i];

            s = new Picture();
            s.setTitle(file.getName());
            s.setUri(Uri.fromFile(file));


            results.add(s);
        
    

    return results;

这是监听文本输入变化的功能

   @Override
public boolean onCreateOptionsMenu(Menu menu) 
    getMenuInflater().inflate(R.menu.main_menu, menu);

    // Associate searchable configuration with the SearchView
    SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
    searchView = (SearchView) menu.findItem(R.id.action_search)
            .getActionView();
    searchView.setSearchableInfo(searchManager
            .getSearchableInfo(getComponentName()));
    searchView.setMaxWidth(Integer.MAX_VALUE);

    // listening to search query text change
    searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() 
        @Override
        public boolean onQueryTextSubmit(String query) 
            // filter recycler view when query submitted
            adapter.getFilter().filter(query);
            return false;
        

        @Override
        public boolean onQueryTextChange(String query) 
            // filter recycler view when text is changed
            adapter.getFilter().filter(query);
            return false;
        
    );
    return true;

希望你们能帮我解决这个问题。

【问题讨论】:

使用Filterable 基本适配器,如this - 示例工作适配器是here - 与Filterable 类一样,过滤是通过调用adapter.getFilter().filter(...) 完成的 感谢先生的快速回复。但是您认为我的代码有什么问题? 我会试试你的解决方案。 谢谢你的时间,@ronginat 找到我在哪里犯了一个无意识的错误。 【参考方案1】:

您的 recyclerview 无法处理过滤后的数据。 当您完成过滤并调用notifyDataSetChanged(); 时,它实际上使用onBindViewHolder 方法将所有可见视图与新内容绑定。 您可以看到,在 onBindViewHolder 中,您从 mData 获取项目,而您应该从 mDataFiltered 获取项目。

【讨论】:

就是这样。它现在很有魅力。谢谢先生。

以上是关于搜索过滤器后如何更新android RecyclerView项目?的主要内容,如果未能解决你的问题,请参考以下文章

搜索后,p:dataTable 不会更新,除非调用了两次搜索或输入并清除了过滤器中的某些内容

如何在android中的简单列表视图上使用startsWith应用搜索过滤器

Android Honeycomb 中的 Bitmap#recycle() 实际上做了啥?

Bitmap.recycle引发的血案

Android系统中Bitmap是不是有调用recycle方法的必要性

如何实现自动搜索文本框,延迟很短?