我想在我的回收站 View 中使用过滤器显示 Realm 查询的结果。 所以我实现了这段代码:
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()
之后,我得到了相同的错误消息...它不一样吗线?还是过滤器有其他问题?
谢谢
最佳答案
问题是您在 UI 线程上查询机场,然后尝试在另一个线程中访问这些相同的对象。这是不允许的。
方法performFiltering在工作线程上运行。当它调用 getFilteredResults
时,它会尝试访问在另一个线程 (UI) 上查询的 Realm 对象的属性 (item.getName()
)。如错误所述,Realm 对象只能在创建它们的线程上访问。
如果您希望能够访问您在另一个线程中查询的对象,您可能希望获得它们的深拷贝,以便它们与 Realm 分离。在您的示例中,查询机场后,您可以使用方法 copyFromRealm()
获取常规 Airport 对象的列表并从中使用它。
关于android - recyclerview 中不正确的线程错误导致的 Realm 访问,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40593806/