我想使用Filter在我的Recycler视图中显示领域查询的结果。 所以我实现了这段代码:
public class ListAirportFragment extends Fragment
{
Realm realm;
List<AirportR>airports = new ArrayList<>();
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState)
{
View rootView = inflater.inflate(R.layout.fragment_list_airport, container, false);
RealmConfiguration defaultConfig = new RealmConfiguration.Builder().deleteRealmIfMigrationNeeded().build();
realm = Realm.getInstance(defaultConfig);
RecyclerView recyclerView = (RecyclerView)rootView.findViewById(R.id.recyclerview);
SearchView searchView = (SearchView)rootView.findViewById(R.id.searchview);
recyclerView.setHasFixedSize(true);
//final RealmResults<AirportR> airps = realm.where(AirportR.class).findAllAsync();
final RealmResults<AirportR> airps = realm.where(AirportR.class).findAll();
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
final AirportAdapter adapter = new AirportAdapter(airports,getActivity());
recyclerView.setAdapter(adapter);
realm.executeTransaction(new Realm.Transaction()
{
@Override
public void execute(Realm realm)
{
for (int i = 0; i<airps.size();i++)
{
airports.add(airps.get(i));
adapter.notifyDataSetChanged();
}
}
});
/* airps.addChangeListener(new RealmChangeListener<RealmResults<AirportR>>() {
@Override
public void onChange(RealmResults<AirportR> element)
{
for (int i = 0; i<element.size();i++)
{
airports.add(element.get(i));
adapter.notifyDataSetChanged();
}
}
}); */
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener()
{
@Override
public boolean onQueryTextSubmit(String query)
{
return false;
}
@Override
public boolean onQueryTextChange(String newText)
{
adapter.getFilter().filter(newText);
return true;
}
});
return rootView;
}
}
这是我的适配器:
public class AirportAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> implements Filterable
{
private List<AirportR>originalAirports;
private List <AirportR>listAirports;
private Context context;
public AirportAdapter(List<AirportR> airports, Context context)
{
this.originalAirports = airports;
this.listAirports = airports;
this.context = context;
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
{
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.airport_show, parent,false);
AirportClass holder = new AirportClass(view);
return holder;
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position)
{
AirportR airportR = originalAirports.get(position);
String country = airportR.getIsoCountry().toLowerCase()+".png";
int imgID = context.getResources().getIdentifier(country , "drawable", context.getPackageName());
AirportClass mHolder = (AirportClass)holder;
mHolder.image.setImageResource(imgID);
mHolder.country.setText(airportR.getIsoCountry());
mHolder.name.setText(airportR.getName());
}
@Override
public int getItemCount()
{
return listAirports.size();
}
@Override
public Filter getFilter()
{
return new Filter()
{
@Override
protected FilterResults performFiltering(CharSequence constraint)
{
List<AirportR> filteredResults = null;
if (constraint.length() == 0)
{
filteredResults = originalAirports;
}
else
{
filteredResults = getFilteredResults(constraint.toString().toLowerCase());
}
Log.d("const",String.valueOf(constraint.length()));
FilterResults results = new FilterResults();
results.values = filteredResults;
return results;
}
protected List<AirportR> getFilteredResults(String constraint)
{
List<AirportR> results = new ArrayList<>();
for (AirportR item : originalAirports)
{
if (item.getName().toLowerCase().contains(constraint))
{
results.add(item);
}
}
return results;
}
@Override
protected void publishResults(CharSequence constraint, FilterResults results)
{
listAirports = (List<AirportR>)results.values;
AirportAdapter.this.notifyDataSetChanged();
}
};
}
private class AirportClass extends RecyclerView.ViewHolder
{
TextView name, country;
ImageView image;
public AirportClass(View itemView)
{
super(itemView);
name = (TextView)itemView.findViewById(R.id.name);
country = (TextView)itemView.findViewById(R.id.country);
image = (ImageView)itemView.findViewById(R.id.imageView);
}
}
}
问题是:当我尝试将某些内容添加到searchView时,它会崩溃,并且使用调试器,我会看到以下错误消息:
W/Filter: An exception occured during performFiltering()!
java.lang.IllegalStateException: Realm access from incorrect thread. Realm objects can only be accessed on the thread they were created.
有什么问题?在我使用findAllAsync()
方法获取结果之前和使用简单findAll()
之后,我得到了相同的错误消息...它不是同一个线程吗?或者过滤器中还有其他问题吗?
由于
答案 0 :(得分:4)
问题是您在UI线程上查询机场,然后尝试在另一个线程中访问这些相同的对象。这是不允许的。
方法performFiltering在工作线程上运行。当它调用getFilteredResults
时,它会尝试访问在另一个线程(UI)上查询的Realm对象的属性(item.getName()
)。正如错误所说,Realm对象只能在创建它们的线程上访问。
如果您希望能够访问在另一个线程中查询的对象,您可能希望获得它们的深层副本,以便它们与Realm分离。在您的示例中,在查询机场后,您可以使用方法copyFromRealm()
获取常规Airport对象的列表并从其上使用它。