问题描述
我遵循了一些有关sqlite和RecyclerView(https://www.youtube.com/watch?v=VQKq9RHMS_0&ab_channel=Stevdza-San)的youtube教程,我完成了所有工作,并根据需要对我的应用程序进行了自定义,一切正常。
现在我要做的就是在顶部(操作栏)添加搜索按钮,以便我可以从RecyclerView中搜索项目。
因此,我试图弄清楚如何实现它,但是我在过滤器和所有这些方面都感到吃力。在CustomeAdpter获得ArrayList的同时,我看到的每个与List(E)一起使用的教程都无法理解如何使其与ArrayList一起使用。
所以,如果有人可以帮助我并给我一些指导,我将不胜感激
编辑
我在适配器中添加了getFilter()
函数,但是当我尝试搜索RecyclerView时什么也没发生。
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
activity = MainActivity.this;
noClubsImage = findViewById(R.id.noClubsImage);
noClubsText = findViewById(R.id.noClubsText);
recyclerView = findViewById(R.id.recyclerView);
add_button = findViewById(R.id.add_button);
add_button.setonClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this,AddActivity.class);
activity.startActivityForResult(intent,1);
}
});
myDB = new MyDatabaseHelper(MainActivity.this);
club_id = new ArrayList<>();
club_name = new ArrayList<>();
join_date = new ArrayList<>();
expire_date = new ArrayList<>();
storeDataInArrays();
customAdapter = new CustomAdapter(MainActivity.this,this,club_id,club_name,join_date,expire_date);
recyclerView.setAdapter(customAdapter);
recyclerView.setLayoutManager(new linearlayoutmanager(MainActivity.this));
}
。 。 。 编辑 ***
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main_menu,menu);
MenuItem item = menu.findItem(R.id.action_search);
SearchView searchView = (SearchView) item.getActionView();
searchView.setonQueryTextListener(new SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String query) {
customAdapter.getFilter().filter(query);
return false;
}
@Override
public boolean onQueryTextChange(String newText) {
customAdapter.getFilter().filter(newText);
return true;
}
});
return super.onCreateOptionsMenu(menu);
}
}
这是我的适配器:
我在onBindViewHolder中添加了Try&catch函数,因为它会崩溃,并得到以下错误:“ java.lang.indexoutofboundsexception:Index:1,Size:1” 添加后,我可以搜索但很奇怪的东西,上传一些图片: When I start the app Start searching "Yasha" -> it change the two rows
public class CustomAdapter extends RecyclerView.Adapter<CustomAdapter.MyViewHolder> implements Filterable{
private Context context;
private Activity activity;
private ArrayList club_id,expire_date,list,originalList;
int position;
Animation translate_anim;
CustomAdapter(Activity activity,Context context,ArrayList club_id,ArrayList club_name,ArrayList join_date,ArrayList expire_date){
this.activity = activity;
this.context = context;
this.club_id = club_id;
this.club_name = club_name;
this.join_date = join_date;
this.expire_date = expire_date;
this.list = club_name;
this.originalList = club_name;
}
@NonNull
@Override
public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent,int viewType) {
LayoutInflater inflater = LayoutInflater.from(context);
View view = inflater.inflate(R.layout.my_row,parent,false);
return new MyViewHolder(view);
}
public Filter getFilter(){
return new Filter() {
@Override
protected FilterResults performFiltering(CharSequence constraint) {
ArrayList filteredResults = null;
if (constraint.length() == 0) {
filteredResults = club_name;
} else {
filteredResults = getFilteredResults(constraint.toString().toLowerCase());
}
FilterResults results = new FilterResults();
results.values = filteredResults;
Log.d("Test",filteredResults.toString());
return results;
}
@Override
protected void publishResults(CharSequence constraint,FilterResults results) {
club_name = (ArrayList<String>) results.values;
notifyDataSetChanged();
}
};
}
protected ArrayList getFilteredResults(String constraint) {
ArrayList results = new ArrayList<>();
for (Object item : originalList) {
if (item.toString().toLowerCase().contains(constraint)) {
results.add(item.toString());
}
}
//Log.d("Test",results.toString());
return results;
}
@Override
public void onBindViewHolder(@NonNull MyViewHolder holder,final int position) {
try{
this.position = position;
holder.club_name_txt.setText(String.valueOf(club_name.get(position)));
holder.join_txt.setText(String.valueOf(join_date.get(position)));
holder.expire_txt.setText(String.valueOf(expire_date.get(position)));
holder.mainLayout.setonClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(context,UpdateActivity.class);
intent.putExtra("club_id",String.valueOf(club_id.get(position)));
intent.putExtra("club_name",String.valueOf(club_name.get(position)));
intent.putExtra("join_date",String.valueOf(join_date.get(position)));
intent.putExtra("expire_date",String.valueOf(expire_date.get(position)));
activity.startActivityForResult(intent,1);
}
});
}catch(Exception ex) {
Log.e("TAG","EXCEPTION CAUGHT WHILE EXECUTING DATABASE TRANSACTION");
ex.printstacktrace();
}
}
@Override
public int getItemCount() {
return club_id.size();
}
public class MyViewHolder extends RecyclerView.ViewHolder {
LinearLayout mainLayout;
TextView club_id_txt,club_name_txt,join_txt,expire_txt;
public MyViewHolder(@NonNull View itemView) {
super(itemView);
club_name_txt = itemView.findViewById(R.id.club_name_txt);
join_txt = itemView.findViewById(R.id.jDate_txt);
expire_txt = itemView.findViewById(R.id.eDate_txt);
mainLayout = itemView.findViewById(R.id.mainLayout);
translate_anim = AnimationUtils.loadAnimation(context,R.anim.translate_anim);
mainLayout.setAnimation(translate_anim);
}
}}
解决方法
在customAdapter.getFilter();
的两种方法中都有OnQueryTextListener
行,它为您返回过滤器。这就是您所请求的所有内容,您从未向此过滤器传递过String
。这条线应该看起来像这样
customAdapter.getFilter().filter(query); // or newText,depend on OnQueryTextListener method
根据评论进行编辑:
删除此try{}catch()
并解决您的异常。这种方法是可靠的,只有您的错误才能导致崩溃。
您仅过滤和发布了一个数组(club_name = (ArrayList<String>) results.values;
),但仍在通知adapter
列表中的项数等于club_id.size();
中的getItemCount
。这就是为什么您获得IndexOutOfBoundsException
-club_id
并保持多个项目的原因,即使club_name
里面只有很少或一个项目时也进行了过滤。您应该过滤所有四个数组,实际上这应该是一个带有所有四个参数的自定义对象的数组
一些修复教程:
将您的数据保留在一些其他数组中,这些数组将保持不变,即使过滤后也保留所有数据。首先创建“原始”和“工作”数组
CustomAdapter(Activity activity,Context context,ArrayList club_id,ArrayList club_name,ArrayList join_date,ArrayList expire_date){
this.activity = activity;
this.context = context;
this.club_id_org = club_id;
this.club_name_org = club_name;
this.join_date_org = join_date;
this.expire_date_org = expire_date;
this.club_id = new ArrayList<>();
this.club_id.addAll(this.club_id_org);
this.club_name = new ArrayList<>();
this.club_name.addAll(this.club_name_org);
this.join_date = new ArrayList<>();
this.join_date.addAll(this.join_date_org);
this.expire_date = new ArrayList<>();
this.expire_date.addAll(this.expire_date_org);
}
请注意这里有多少重复的代码,这就是为什么它应该是一个带有自定义对象的ArrayList
...但是nvm,让(暂时)保留四个数组
不要使用这种构造:this.list = club_name;
-这使list
和club_name
是相同的数组(对象),当您从一个项目中删除某些项目时,它将从第二个项目中删除(在事实相同)数组,我们这里需要两个分开的数组(x4)
现在所有后缀为_org
的数组都包含整个列表,但是适配器应该在“工作”的数组上工作,而这些数组没有_org
,就像您当前在代码中一样
现在过滤:在performFiltering
中,您应该再次创建四个临时数组,并用过滤后的项目填充它们。通过_org
数组过滤迭代,这些数组包含所有项
@Override
protected FilterResults performFiltering(CharSequence constraint) {
ArrayList club_id_temp = new Arraylist<>(),club_name_temp = new Arraylist<>(),join_date_temp = new Arraylist<>(),expire_date_temp = new Arraylist<>();
if (constraint.length() == 0) {
club_id_temp.addAll(club_id_org);
club_name_temp.addAll(club_name_org);
join_date_temp.addAll(join_date_org);
expire_date_temp.addAll(expire_date_org);
} else {
for(int i=0; i<club_name_org.size(); i++){
if(club_name_org.get(i).toLowerCase().contains(constraint.toLowerCase())){
club_id_temp.add(club_id_org.get(i));
club_name_temp.add(club_name_org.get(i));
join_date_temp.add(join_date_org.get(i));
expire_date_temp.add(expire_date_org.get(i));
}
}
}
FilterResults results = new FilterResults();
results.values = ...
现在我们有一个小问题……results.values
只能携带一个物体,例如一个ArrayList
,而您有四个...让make class随身携带所有四个,例如声明。在适配器的底部(恰好在最后一个括号关闭整个适配器}
之前)
public static class TempArrays{
public ArrayList club_id,club_name,join_date,expire_date;
}
并将所有四个过滤后的数组打包到:
FilterResults results = new FilterResults();
TempArrays ta = new TempArrays();
ta.club_id = club_id_temp;
ta.club_name = club_name_temp;
ta.join_date = join_date_temp;
ta.expire_date = expire_date_temp;
results.values = ta;
return results;
}
并在publishResults
中解压缩此构造:
@Override
protected void publishResults(CharSequence constraint,FilterResults results) {
TempArrays ta = (TempArrays) results.values;
club_id = ta.club_id;
club_name = ta.club_name;
join_date = ta.join_date;
expire_date = ta.expire_date;
notifyDataSetChanged();
}
再次:四个数组是不正确的方法,看看我们这里有多少重复的行... +一些较小的解决方法,以便在过滤后传递所有四个而不是一个......实际上应该有一些{{1} }类,与此类似
ClubModel
,然后您可以处理一个包含public static class ClubModel{
public String club_id,expire_date;
}
个项目的数组,而不是四个数组。查看POJO的定义