kunusann
@kunusann

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

Collectionの特定の位置に要素を追加したい

解決したいこと

RealmとRecyclerViewでtodoアプリを作成したいです。
ドラッグアンドドロップでリスト項目の並び替えを実装するために、ItemTouchHelperを使っています。

onMove()の中でドラッグした項目をドロップした位置に移動したいのですが、
add(int 追加位置, Object 追加する要素)のメソッドを使うとdeprecatedのエラーが出てしましい、このメソッドを実行した時点でアプリが落ちてしまいます。

発生している問題・エラー

上記add()のdeprecatedエラーが出てしまい、実装方法が分からず困っています。
代替となるメソッドを探したのですが、いっこうに見つからないので初めて質問をします。説明不足な点があったらすみません。
宜しくお願いします。
```
E/InputEventReceiver: Exception dispatching input event.
D/AndroidRuntime: Shutting down VM
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.simpletodo, PID: 15243
java.lang.UnsupportedOperationException: This method is not supported by 'RealmResults' or 'OrderedRealmCollectionSnapshot'.
at io.realm.OrderedRealmCollectionImpl.add(OrderedRealmCollectionImpl.java:528)
at io.realm.RealmResults.add(RealmResults.java:69)
at com.example.simpletodo.MainActivity$onCreate$itHelper$1$onMove$1.execute(MainActivity.kt:80)
at io.realm.Realm.executeTransaction(Realm.java:1489)
at com.example.simpletodo.MainActivity$onCreate$itHelper$1.onMove(MainActivity.kt:76)
at androidx.recyclerview.widget.ItemTouchHelper.moveIfNecessary(ItemTouchHelper.java:881)
at androidx.recyclerview.widget.ItemTouchHelper$2.onTouchEvent(ItemTouchHelper.java:387)
at androidx.recyclerview.widget.RecyclerView.dispatchToOnItemTouchListeners(RecyclerView.java:3124)
at androidx.recyclerview.widget.RecyclerView.onTouchEvent(RecyclerView.java:3283)
at android.view.View.dispatchTouchEvent(View.java:12513)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3024)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2705)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3030)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2719)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3030)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2719)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3030)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2719)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3030)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2719)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3030)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2719)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3030)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2719)
at com.android.internal.policy.DecorView.superDispatchTouchEvent(DecorView.java:440)
at com.android.internal.policy.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1830)
at android.app.Activity.dispatchTouchEvent(Activity.java:3400)
at androidx.appcompat.view.WindowCallbackWrapper.dispatchTouchEvent(WindowCallbackWrapper.java:69)
at com.android.internal.policy.DecorView.dispatchTouchEvent(DecorView.java:398)
at android.view.View.dispatchPointerEvent(View.java:12752)
at android.view.ViewRootImpl$ViewPostImeInputStage.processPointerEvent(ViewRootImpl.java:5106)
at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:4909)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4426)
at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:4479)
at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:4445)
at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:4585)
at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:4453)
at android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:4642)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4426)
at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:4479)
at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:4445)
at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:4453)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4426)
at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:7092)
at android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:7061)
at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:7022)
at android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent(ViewRootImpl.java:7195)
at android.view.InputEventReceiver.dispatchInputEvent(InputEventReceiver.java:186)
at android.view.InputEventReceiver.nativeConsumeBatchedInputEvents(Native Method)
E/AndroidRuntime: at android.view.InputEventReceiver.consumeBatchedInputEvents(InputEventReceiver.java:177)
at android.view.ViewRootImpl.doConsumeBatchedInput(ViewRootImpl.java:7166)
at android.view.ViewRootImpl$ConsumeBatchedInputRunnable.run(ViewRootImpl.java:7218)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:949)
at android.view.Choreographer.doCallbacks(Choreographer.java:761)
at android.view.Choreographer.doFrame(Choreographer.java:690)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:935)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6669)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
I/Process: Sending signal. PID: 15243 SIG: 9

### 該当するソースコード
```kotlin
package com.example.simpletodo

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.CheckBox
import android.widget.EditText
import android.widget.TextView
import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import io.realm.Realm
import io.realm.RealmResults
import io.realm.kotlin.createObject
import io.realm.kotlin.where
import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.android.synthetic.main.todo_list_row.*

class MainActivity : AppCompatActivity() {
    private lateinit var realm: Realm

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        //タスクバーの非表示
        supportActionBar?.hide()

        //realmのインスタンスを取得
        realm = Realm.getDefaultInstance()

        //レイアウトマネージャーの設定
        list.layoutManager = LinearLayoutManager(this)

        //TodoのCollectionを返す
        val todos = realm.where<Todo>().findAll()
        val adapter = TodoAdapter(todos)
        list.adapter = adapter

        //saveボタン押下時に、新しいtodoを登録
        save.setOnClickListener {
            val todo: String = addTodo.text.toString()
            if (!"".equals(todo)) {
                realm.executeTransaction {
                    val maxId = it.where<Todo>().max("id")
                    val nextId = (maxId?.toLong() ?: 0L) + 1
                    //Primary Keyを与えて、引数型のオブジェクトを生成する
                    val newTodo = it.createObject<Todo>(nextId)
                    newTodo.todo = todo

                    //追加後は空文字に戻す
                    addTodo.setText("")
                }
            }
        }

        //fab押下時、チェック済みのtodoを一括削除
        fab.setOnClickListener {
            realm.executeTransaction {
                realm.where<Todo>().equalTo("isChecked", true).findAll().deleteAllFromRealm()
                //adapter positionを合わせるため、データセットの変更を伝える
                adapter.notifyDataSetChanged()
            }
        }

        //ItemTouchHelper
        val itHelper = ItemTouchHelper(
            object: ItemTouchHelper.SimpleCallback(ItemTouchHelper.UP or ItemTouchHelper.DOWN, ItemTouchHelper.LEFT) {
                override fun onMove(
                    recyclerView: RecyclerView,
                    viewHolder: RecyclerView.ViewHolder,
                    target: RecyclerView.ViewHolder
                ): Boolean {
                    val fromPosition = viewHolder?.adapterPosition
                    val toPosition = target?.adapterPosition

                    realm.executeTransaction {
                        //ここでドロップ位置にドラッグしている項目を挿入したいです
                        val movingTodo = todos.get(fromPosition)
                        todos.deleteFromRealm(fromPosition)
                        todos.add(toPosition, movingTodo)


                    }
                    //Adapterにドラッグアンドドロップされたことを通知します。
                    adapter.notifyItemMoved(fromPosition, toPosition)
                    return true
                }


                override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
                    viewHolder.let {
                        realm.executeTransaction {
                            todos.deleteFromRealm(viewHolder.adapterPosition)
                        }
                        adapter.notifyItemRemoved(viewHolder.adapterPosition)
                    }
                }

            }
        )
        itHelper.attachToRecyclerView(list)

    }

    override fun onDestroy() {
        super.onDestroy()
        realm.close()
    }
}

0

2Answer

Realm や Java は触ったことがないのですが
findAll した結果の順序を変更してもデータの本体が入っているデータベースでの順序は変わらないと思います。

順序を管理するためのカラムを追加してそれを操作するような実装にしてみてはどうでしょうか。

一時的に(表示用などで)順序を変更したいのであれば一旦 List などに入れ直しても良いと思います。

1Like

Your answer might help someone💌