RecyclerView(自定义适配器)不刷新搜索列表

Posted

技术标签:

【中文标题】RecyclerView(自定义适配器)不刷新搜索列表【英文标题】:RecyclerView (Custom Adapter) not refreshing the List on search 【发布时间】:2021-10-12 09:37:15 【问题描述】:

这是我在 *** 上的第一个问题。我最近才开始进行 android 开发。


我想做的事:

我有一个人员列表,我想根据用户在我的工具栏(不是 ActionBar)的搜索框中的输入来过滤/搜索 RecyclerView(使用自定义适配器)列表 (Initial List)。

我的问题:

最初,什么都没有发生。这份名单根本没有改变。现在,列表发生了变化,但无论输入什么,都只会显示一个固定列表项(Current Search output)。我的回收器适配器没有刷新到新的过滤列表。而且我在 bulid 或 logcat 中没有收到任何错误。

我尝试过的:

经过一整天的调试,并在我的布局管理器和 RecycleView 适配器中修复了一些“NullPointerExceptions”,并尝试了 2 种不同的过滤方法。即使我能够生成filtered array (List values in Logcat),我也无法得到结果。我尝试使用“notifyDataSetChanged()”、“notifyItemRangeChanged()”和“*notifyAll();,但都是徒劳的......

请帮忙.....

公共类 MainActivity 扩展 AppCompatActivity

ArrayList<Consultant> consultants= new ArrayList<>();
ArrayList<Consultant> allConsultants = new ArrayList<>();
int rating=5;
int price = 10000;

String categoryFilter;
String ratingFilter;

RecyclerView recyclerView;
Consultant_RecyclerAdapter.RecyclerViewClickListener listener;
Consultant_RecyclerAdapter adapter= new Consultant_RecyclerAdapter(consultants,listener);

Spinner s_categories;
Spinner s_rating;

@Override
protected void onCreate(Bundle savedInstanceState) 
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    Toolbar toolbar = findViewById(R.id.toolbar);
    setSupportActionBar(toolbar);

    recyclerView= findViewById(R.id.RecycleView);


    s_categories=findViewById(R.id.Spinner_Category);
    s_rating=findViewById(R.id.Spinner_Rating);

    addToList();
    setUpAdapter();


private void setUpAdapter() 
    Log.i("Adapter","Started");
    setOnClickListener();
    Consultant_RecyclerAdapter adapter = new Consultant_RecyclerAdapter(consultants,listener);
    recyclerView.setLayoutManager(new LinearLayoutManager(this));
    recyclerView.setItemAnimator(new DefaultItemAnimator());
    recyclerView.setAdapter(adapter);
    Log.i("Adapter","Ended");

private void addToList()
    consultants.add(new Consultant("Dr Kapoor", "consultant_id", "profilePic_src", new String[]"Dentist","Dermatology", 1000, 5));
    consultants.add(new Consultant("Dr Pankaj Kumar", "consultant_id", "profilePic_src", new String[]"Psychology","Respiratory", 3000, 1));
    consultants.add(new Consultant("Dr Harsh Jha", "consultant_id", "profilePic_src", new String[]"Internal Medicine", 1500, 5));
    consultants.add(new Consultant("Dr Gaurav Singh", "consultant_id", "profilePic_src", new String[]"Dentist","Cardiologist", 3500, 4));
    consultants.add(new Consultant("Dr Aman", "consultant_id", "profilePic_src", new String[]"Lungs","Neuro", 1000, 2));
    consultants.add(new Consultant("Dr Jatin Chabra", "consultant_id", "profilePic_src", new String[]"Psychology", 5000, 3));
    Log.i("List","Done");
    allConsultants=new ArrayList<>(consultants);

private void setOnClickListener() 
    listener = new Consultant_RecyclerAdapter.RecyclerViewClickListener() 
        @Override
        public void onClick(View v, int position) 
           Intent intent = new Intent(getApplicationContext(), ConsultantProfileActivity.class);
            intent.putExtra("consultant_name", consultants.get(position).getName());
            intent.putExtra("pic_src", consultants.get(position).getProfilePic_src());
            intent.putExtra("about", consultants.get(position).getAbout());
            intent.putExtra("consultant_id",consultants.get(position).getConsultant_id());
            intent.putExtra("categories",consultants.get(position).getCategories());

            startActivity(intent);
        
    ;



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

    MenuItem menuItem = menu.findItem(R.id.action_search);
    SearchView searchView = (SearchView) menuItem.getActionView();
    searchView.setQueryHint("Search....");
    searchView.setImeOptions(EditorInfo.IME_ACTION_DONE);

    searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() 
        @Override
        public boolean onQueryTextSubmit(String query) 
            return false;
        

        @Override
        public boolean onQueryTextChange(String newText) 
            Log.i("Search","QueryChanged");
            //adapter.getFilter().filter(newText);
            filter(newText);
            return false    ;
        
    );
    return true;


private void filter(String text) 
    // creating a new array list to filter our data.
    ArrayList<Consultant> filteredlist = new ArrayList<>();

    // running a for loop to compare elements.
    for (Consultant item : allConsultants) 
        Log.i("Filter: ",item.getName()+"...."+text);

        // checking if the entered string matched with any item of our recycler view.
        if (item.getName().toLowerCase().contains(text.toLowerCase())) 
            Log.i("Match","Found");
            // if the item is matched we are
            // adding it to our filtered list.
            filteredlist.add(item);
        
    
    Log.i("Filter: ",(filteredlist.toString()));

    if (filteredlist.isEmpty()) 
        // if no item is added in filtered list we are
        // displaying a toast message as no data found.
        Toast.makeText(this, "No Data Found..", Toast.LENGTH_SHORT).show();
     else 
        // at last we are passing that filtered
        // list to our adapter class.
        adapter.filterList(filteredlist);
    


请忽略下面Recycler Adapter中的搜索方式,我目前正在使用mainActivity中的搜索方式

公共类 Consultant_RecyclerAdapter 扩展 RecyclerView.Adapter ArrayList 顾问; ArrayList AllConsultants,preFilteredList;

private RecyclerViewClickListener listener;

public Consultant_RecyclerAdapter(ArrayList<Consultant> consultants, RecyclerViewClickListener listener) 
    this.consultants = consultants;
    this.listener = listener;
    //AllConsultants = new ArrayList<>(consultants);
    //preFilteredList = new ArrayList<>(consultants);



//NOTIFYING THE ADAPTER ABOUT UPDATE


public void filterList(ArrayList<Consultant> filteredlist) 

    consultants.clear();

    consultants.addAll(filteredlist);

    notifyDataSetChanged();






public class MyViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener 


    private TextView name, rating, price, category;
    private ImageView profile;

    public MyViewHolder(@NonNull View view) 
        super(view);
        name = view.findViewById(R.id.textView_Name);
        profile = view.findViewById(R.id.imageView_ProfilePic);
        category = view.findViewById(R.id.textView_Category);
        rating = view.findViewById(R.id.textView_Rating);
        price = view.findViewById(R.id.textView_Price);
        view.setOnClickListener(this);
    

    @Override
    public void onClick(View view) listener.onClick(view, getAdapterPosition()); 


@NonNull
@Override
public Consultant_RecyclerAdapter.MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) 
    View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.consultant_list_item, parent, false);
    return new MyViewHolder(itemView);


@Override
public void onBindViewHolder(@NonNull MyViewHolder holder, int position) 
    String name = consultants.get(position).getName();
    String profilePic_src = consultants.get(position).getProfilePic_src();
    float rating = consultants.get(position).getRating();
    String categories = "";
    //Converting Array to string
    for (String i : consultants.get(position).getCategories()) 
        categories = i + ", " + categories;
    
    int price = consultants.get(position).getPrice();

    holder.name.setText(name);
    holder.category.setText(categories);
    holder.price.setText(String.valueOf(price));
    holder.rating.setText(String.valueOf(rating));
    holder.profile.setImageResource(R.drawable.consultant);

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


public interface RecyclerViewClickListener 
    void onClick(View v, int position);


    public void listUpdate(String categoryFilter, String ratingFilter) 
    preFilteredList = new ArrayList<>();

    if (categoryFilter != null || ratingFilter != null) 
        for (Consultant item : AllConsultants) 
            if (String.valueOf(item.getRating()).toLowerCase(Locale.ROOT).contains(ratingFilter) && item.getCategories().toString().toLowerCase(Locale.ROOT).contains(categoryFilter)) 
                preFilteredList.add(item);
            
        
    else
        preFilteredList= new ArrayList<Consultant>(AllConsultants);
    
    consultants.clear();
    consultants.addAll(preFilteredList);
    getFilter();



@Override
public Filter getFilter() 
    return theFilter;


public Filter theFilter = new Filter() 
    @Override
    protected FilterResults performFiltering(CharSequence constraint) 
        List<Consultant> filteredList = new ArrayList<>();

        if (constraint == null || constraint.length() == 0) 
            filteredList.addAll(AllConsultants);
         else 
            String filterPattern = constraint.toString().toLowerCase().trim();

            for (Consultant item : AllConsultants) 
                Log.i("Filter: ",item.getName()+"...."+filterPattern);
                if (item.getName().toLowerCase().contains(filterPattern)) 
                    Log.i("Match","Found");
                    filteredList.add(item);
                
            
        

        FilterResults results = new FilterResults();
        results.values = filteredList;

        return results;
    

    @Override
    protected void publishResults(CharSequence constraint, FilterResults results) 
        Log.i("Filter ","Published");
        consultants.clear();
        consultants.addAll((List) results.values);
        notifyDataSetChanged();

    
;

【问题讨论】:

【参考方案1】:

不要使用活动来过滤结果,这会降低性能。在 Adapter 中使用 Filterable 接口,它在后台线程上执行过滤并将结果发布到主线程上。我看到你已经实现了。

通过查看您的适配器代码,我认为它应该可以工作,因为您维护了两个列表 completefiltered 的不同引用。

我的罪魁祸首是您已将适配器初始化为全局变量,但您设置为 RecyclerView 的适配器是您在本地创建的另一个适配器。解决这个问题,它应该可以工作。

private Consultant_RecyclerAdapter adapter ; // Global variable


private void setUpAdapter() 
Log.i("Adapter","Started");
setOnClickListener();
adapter = new Consultant_RecyclerAdapter(consultants,listener);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.setItemAnimator(new DefaultItemAnimator());
recyclerView.setAdapter(adapter);
Log.i("Adapter","Ended");

【讨论】:

刚刚试过这个。错误:java.lang.NullPointerException: at java.util.ArrayList.addAll(ArrayList.java:588) at (Consultant_RecyclerAdapter.java:157) Consultant_RecyclerAdapter.java:157=> advisors.addAll((List) results.values); RecyclerView 适配器中的最后 6 行。我是android dev的新手,如果您能进一步指导我,那将非常有帮助 尝试将适配器中的consulatant ArrayList 设置为私有/公共。还是不行

以上是关于RecyclerView(自定义适配器)不刷新搜索列表的主要内容,如果未能解决你的问题,请参考以下文章

notifyDataSetChange 不适用于 RecyclerView [重复]

一个漂亮而强大的RecyclerView

Android:重新绑定 ListView 或 RecyclerView 而不刷新 Header

支持下拉刷新和上划加载更多的自定义RecyclerView(仿XListView效果)

在 recyclerview 适配器类中显示自定义弹出窗口 - Android Java

Android RecyclerView 和自定义 Adapter 位置元素的变化