web-dev-qa-db-ja.com

Android-レルム-オブジェクトの削除-オブジェクトは操作できなくなりました

RecyclerViewデータベースから入力されたRealmからアイテムを削除しようとすると、次のエラーが発生します。

Java.lang.IllegalStateException: Illegal State: 
Object is no longer valid to operate on. Was it deleted by another thread?

前提条件すでに削除されているときにアクセスを試みていると思いますが、どこにあるのかわかりません。

Context:都市のリストを表示していて、アイテムをlongClickすると、削除の確認を求めるダイアログが表示されます。

アプリを再起動すると、そのアイテムはデータベースから削除されます。

レルムから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;
            }
        });
    }
}
}
9
Isabelle

さて、あなたは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), new DialogInterface.OnClickListener() {
    @Override
    public void onClick(DialogInterface dialogInterface, 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, 
                           OnItemClickListener onItemClickListener, 
                           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()が呼び出されます。

6
EpicPandaForce