我正在尝试从Realm数据库填充的RecyclerView中删除一个项目,我收到以下错误:
java.lang.IllegalStateException: Illegal State: Object is no longer valid to operate on. Was it deleted by another thread?
假设
我猜我正在尝试访问它已被删除,但我不明白在哪里.
语境:
我正在显示一个城市列表并且长按一个项目会显示一个对话框,要求确认删除.
该项目在数据库中被删除,因为当我重新启动应用程序时,它已不存在了.
领域到ArrayList
public static ArrayList<City> getStoredCities(){ RealmQuery<City> query = getRealmInstance().where(City.class); final RealmResults<City>results = realm.where(City.class) .findAllSorted("timestamp",Sort.DESCENDING); results.size(); ArrayList<City> cityArrayList = new ArrayList<>(); for(int i = 0; i< results.size(); i++){ cityArrayList.add(results.get(i)); } return cityArrayList; }
对话框代码
builder.setPositiveButton(getString(R.string.ok),new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialogInterface,int i) { RealmHelper.removeCity(cityArrayList.get(position)); cityArrayList.remove(position); mRecyclerView.removeViewAt(position); mCityListAdapter.notifyItemRemoved(position); mCityListAdapter.notifyItemRangeChanged(position,cityArrayList.size()); mCityListAdapter.notifyDataSetChanged(); } });
public static void removeCity(City city){ RealmResults<City> result = realm.where(City.class).equalTo("cityName",city.getCityName()).findAll(); realm.beginTransaction(); result.deleteAllFromRealm(); realm.commitTransaction(); }
日志
07-28 11:02:08.461 9461-9461/com.ilepez.weatherapp E/AndroidRuntime: FATAL EXCEPTION: main Process: com.ilepez.weatherapp,PID: 9461 java.lang.IllegalStateException: Illegal State: Object is no longer valid to operate on. Was it deleted by another thread? at io.realm.internal.UncheckedRow.nativeGetString(Native Method) at io.realm.internal.UncheckedRow.getString(UncheckedRow.java:153) at io.realm.CityRealmProxy.realmGet$cityName(CityRealmProxy.java:75) at com.ilepez.weatherapp.data.model.City.getCityName(City.java:41) at com.ilepez.weatherapp.adapter.CityListAdapter.onBindViewHolder(CityListAdapter.java:56) at com.ilepez.weatherapp.adapter.CityListAdapter.onBindViewHolder(CityListAdapter.java:20) at android.support.v7.widget.RecyclerView$Adapter.onBindViewHolder(RecyclerView.java:5768) at android.support.v7.widget.RecyclerView$Adapter.bindViewHolder(RecyclerView.java:5801) at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:5037) at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:4913) at android.support.v7.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:2029) at android.support.v7.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1414) at android.support.v7.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1377) at android.support.v7.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:588) at android.support.v7.widget.RecyclerView.dispatchLayoutStep2(RecyclerView.java:3260) at android.support.v7.widget.RecyclerView.onMeasure(RecyclerView.java:2788) at android.view.View.measure(View.java:20151) at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6328) at android.widget.FrameLayout.onMeasure(FrameLayout.java:194) at android.support.design.widget.NavigationView.onMeasure(NavigationView.java:218) at android.view.View.measure(View.java:20151) at android.support.v4.widget.DrawerLayout.onMeasure(DrawerLayout.java:1108) at android.view.View.measure(View.java:20151) at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6328) at android.widget.FrameLayout.onMeasure(FrameLayout.java:194) at android.support.v7.widget.ContentFrameLayout.onMeasure(ContentFrameLayout.java:135) at android.view.View.measure(View.java:20151) at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6328) at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1464) at android.widget.LinearLayout.measureVertical(LinearLayout.java:747) at android.widget.LinearLayout.onMeasure(LinearLayout.java:629) at android.view.View.measure(View.java:20151) at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6328) at android.widget.FrameLayout.onMeasure(FrameLayout.java:194) at android.view.View.measure(View.java:20151) at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6328) at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1464) at android.widget.LinearLayout.measureVertical(LinearLayout.java:747) at android.widget.LinearLayout.onMeasure(LinearLayout.java:629) at android.view.View.measure(View.java:20151) at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6328) at android.widget.FrameLayout.onMeasure(FrameLayout.java:194) at com.android.internal.policy.PhoneWindow$DecorView.onMeasure(PhoneWindow.java:3158) at android.view.View.measure(View.java:20151) at android.view.ViewRootImpl.performMeasure(ViewRootImpl.java:2594) at android.view.ViewRootImpl.measureHierarchy(ViewRootImpl.java:1549) at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1841) at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1437) at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:7403) at android.view.Choreographer$CallbackRecord.run(Choreographer.java:920) at android.view.Choreographer.doCallbacks(Choreographer.java:695) at android.view.Choreographer.doFrame(Choreographer.java:631) at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:906) at android.os.Handler.handleCall
适配器代码
public class CityListAdapter extends RecyclerView.Adapter<CityListAdapter.CityListViewholder>{ public interface OnItemClickListener{ void onItemClick(int position); } public interface OnItemLongClickListener{ void onItemLongClick(int position); } private static final String LOG_TAG = CityListAdapter.class.getSimpleName(); private ArrayList<City> cityArrayList = new ArrayList<>(); private Context mContext; private OnItemClickListener onItemClickListener; private OnItemLongClickListener onItemLongClickListener; public CityListAdapter(Context context,ArrayList<City> cityArrayList,OnItemClickListener onItemClickListener,OnItemLongClickListener onItemLongClickListener) { this.cityArrayList = cityArrayList; this.mContext = context; this.onItemClickListener = onItemClickListener; this.onItemLongClickListener = onItemLongClickListener; } @Override public CityListViewholder onCreateViewHolder(ViewGroup parent,int viewType) { View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.city_item_navigation_viewholder,null); CityListViewholder cityListViewholder = new CityListViewholder(view,parent.getContext()); return cityListViewholder; } @Override public void onBindViewHolder(CityListViewholder holder,int position) { holder.cityName.setText(cityArrayList.get(position).getCityName()); holder.bindClick(position,onItemClickListener); holder.bindLongClick(position,onItemLongClickListener); } @Override public int getItemCount() { return cityArrayList.size(); } public class CityListViewholder extends RecyclerView.ViewHolder{ TextView cityName; ImageView cityIcon; public CityListViewholder(View itemView,Context context) { super(itemView); cityName = (TextView)itemView.findViewById(R.id.city_name); cityIcon = (ImageView)itemView.findViewById(R.id.city_icon); } public void bindClick(final int position,final OnItemClickListener onItemClickListener){ itemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { onItemClickListener.onItemClick(position); } }); } public void bindLongClick(final int position,final OnItemLongClickListener onItemLongClickListener) { itemView.setOnLongClickListener(new View.OnLongClickListener() { @Override public boolean onLongClick(View view) { onItemLongClickListener.onItemLongClick(position); return true; } }); } } }
解决方法
好的,所以你正在调用adapter.notifyDataSetChanged(),所以任何其他的notify___方法都是不必要的(数据集更改无论如何都会禁用动画.)
在这种情况下,最简单(也是最有效)的方法是直接使用RealmResults,而不是将每个元素检索到ArrayList中,然后使用完全相同的方式.
所以它应该是这样的
public static RealmResults<City> getStoredCities(){ RealmQuery<City> query = getRealmInstance().where(City.class); return realm.where(City.class) .findAllSorted("timestamp",Sort.DESCENDING); }
和
public static void removeCity(City city){ final String cityName = city.getCityName(); realm.executeTransaction(new Realm.Transaction() { @Override public void execute(Realm realm) { RealmResults<City> result = realm.where(City.class).equalTo("cityName",cityName).findAll(); result.deleteAllFromRealm(); } }); }
和
builder.setPositiveButton(getString(R.string.ok),int i) { RealmHelper.removeCity(getItem(position)); } });
和
// dependency: compile 'io.realm:android-adapters:1.3.0' // <-- for Realm 3.x+,use 2.0.0 // for Realm 5.x+,use 3.0.0 public class CityListAdapter extends RealmRecyclerViewAdapter<City,CityListViewHolder> { OnItemClickListener onItemClickListener; OnItemLongClickListener onItemLongClickListener; public CityListAdapter(@NonNull Context context,@Nullable OrderedRealmCollection<City> data,OnItemLongClickListener onItemLongClickListener) { super(context,data,true); this.onItemClickListener = onItemClickListener; this.onItemLongClickListener = onItemLongClickListener; } @Override public CityListViewholder onCreateViewHolder(ViewGroup parent,int viewType) { View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.city_item_navigation_viewholder,parent,false); CityListViewholder cityListViewholder = new CityListViewholder(view,parent.getContext()); return cityListViewholder; } @Override public void onBindViewHolder(CityListViewholder holder,int position) { holder.cityName.setText(getItem(position).getCityName()); holder.bindClick(position,onItemClickListener); holder.bindLongClick(position,onItemLongClickListener); } public static class CityListViewholder extends RecyclerView.ViewHolder { TextView cityName; ImageView cityIcon; public CityListViewholder(View itemView,Context context) { super(itemView); cityName = (TextView)itemView.findViewById(R.id.city_name); cityIcon = (ImageView)itemView.findViewById(R.id.city_icon); } public void bindClick(final int position,final OnItemClickListener onItemClickListener){ itemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { onItemClickListener.onItemClick(position); } }); } public void bindLongClick(final int position,final OnItemLongClickListener onItemLongClickListener) { itemView.setOnLongClickListener(new View.OnLongClickListener() { @Override public boolean onLongClick(View view) { onItemLongClickListener.onItemLongClick(position); return true; } }); } } }
每当结果发生变化时,使用RealmRecyclerViewAdapter都会调用notifyDataSetChanged().