在recyclerview中从错误的线程错误访问领域

时间:2016-11-14 16:48:23

标签: android multithreading android-recyclerview realm

我想使用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()之后,我得到了相同的错误消息...它不是同一个线程吗?或者过滤器中还有其他问题吗?

由于

1 个答案:

答案 0 :(得分:4)

问题是您在UI线程上查询机场,然后尝试在另一个线程中访问这些相同的对象。这是不允许的。

方法performFiltering在工作线程上运行。当它调用getFilteredResults时,它会尝试访问在另一个线程(UI)上查询的Realm对象的属性(item.getName())。正如错误所说,Realm对象只能在创建它们的线程上访问。

如果您希望能够访问在另一个线程中查询的对象,您可能希望获得它们的深层副本,以便它们与Realm分离。在您的示例中,在查询机场后,您可以使用方法copyFromRealm()获取常规Airport对象的列表并从其上使用它。