android - recyclerview 中不正确的线程错误导致的 Realm 访问

标签 android multithreading android-recyclerview realm

我想在我的回收站 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/

相关文章:

android - RecyclerView 问题与 scrollToPosition

android 在另一个应用程序上共享内容时显示错误

java - 使用线程和 ProcessBuilder

java - RecyclerView Espresso 测试因 RunTimeException 失败

c# - C#中的线程

c# - 线程和 session 对 asp.net c# 中的 paypal 机制的影响应该是什么

android - 无尽的回收者 View 重复 json 数据

android - 在Flutter中将数据从一页传递到另一页

java - Android 中 JAXB 的标准等效项

android - NFC广播问题