前提・実現したいこと
Realmを使ってスケジュールアプリを作っています。io.realm:realm-gradle-pluginのバージョンを7.0.8から10.0.1にした上で保存ボタンを押下するとio.realm.exceptions.RealmExceptionが発生してアプリがクラッシュします。バージョン7.0.8ではこのようなエラーは起きていませんでした。
発生している問題・エラーメッセージ
E/AndroidRuntime: FATAL EXCEPTION: main Process: com.example.myscheduler, PID: 10772 io.realm.exceptions.RealmException: Running transactions on the UI thread has been disabled. It can be enabled by setting 'RealmConfiguration.Builder.allowWritesOnUiThread(true)'. at io.realm.BaseRealm.checkAllowWritesOnUiThread(BaseRealm.java:541) at io.realm.Realm.executeTransaction(Realm.java:1533) at com.example.myscheduler.ScheduleEditActivity$onCreate$1.onClick(ScheduleEditActivity.kt:40) at android.view.View.performClick(View.java:7448) at android.view.View.performClickInternal(View.java:7425) at android.view.View.access$3600(View.java:810) at android.view.View$PerformClick.run(View.java:28305) at android.os.Handler.handleCallback(Handler.java:938) at android.os.Handler.dispatchMessage(Handler.java:99) at android.os.Looper.loop(Looper.java:223) at android.app.ActivityThread.main(ActivityThread.java:7656) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
該当のソースコード
MainActivity.kt
package com.example.myscheduler import android.content.Intent import android.os.Bundle import androidx.appcompat.app.AppCompatActivity import androidx.recyclerview.widget.LinearLayoutManager import com.google.android.material.snackbar.Snackbar import io.realm.Realm import io.realm.kotlin.where import kotlinx.android.synthetic.main.activity_main.* import kotlinx.android.synthetic.main.content_main.* class MainActivity : AppCompatActivity() { private lateinit var realm: Realm override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) setSupportActionBar(toolbar) realm = Realm.getDefaultInstance() list.layoutManager = LinearLayoutManager(this) val schedules = realm.where<Schedule>().findAll() val adapter = ScheduleAdapter(schedules) list.adapter = adapter fab.setOnClickListener { view -> val intent = Intent(this, ScheduleEditActivity::class.java) startActivity(intent) } adapter.setOnItemClickListener { id -> val intent = Intent(this, ScheduleEditActivity::class.java) .putExtra("schedule_id", id) startActivity(intent) } } override fun onDestroy() { super.onDestroy() realm.close() } }
MySchedulerApplication.kt
package com.example.myscheduler import android.app.Application import io.realm.Realm class MySchedulerApplication : Application() { override fun onCreate() { super.onCreate() Realm.init(this) } }
Schedule.kt
package com.example.myscheduler import io.realm.RealmObject import io.realm.annotations.PrimaryKey import java.util.* open class Schedule : RealmObject() { @PrimaryKey var id: Long = 0 var date: Date = Date() var title: String = "" var detail: String = "" }
ScheduleAdapter.kt
package com.example.myscheduler import android.text.format.DateFormat import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.TextView import androidx.recyclerview.widget.RecyclerView import io.realm.OrderedRealmCollection import io.realm.RealmRecyclerViewAdapter class ScheduleAdapter(data: OrderedRealmCollection<Schedule>) : RealmRecyclerViewAdapter<Schedule, ScheduleAdapter.ViewHolder>(data, true) { private var listener: ((Long?) -> Unit)? = null fun setOnItemClickListener(listener: (Long?) -> Unit) { this.listener = listener } init { setHasStableIds(true) } class ViewHolder(cell: View) : RecyclerView.ViewHolder(cell) { val date: TextView = cell.findViewById(android.R.id.text1) val title: TextView = cell.findViewById(android.R.id.text2) } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ScheduleAdapter.ViewHolder { val infrater = LayoutInflater.from(parent.context) val view = infrater.inflate( android.R.layout.simple_list_item_2, parent, false ) return ViewHolder(view) } override fun onBindViewHolder(holder: ScheduleAdapter.ViewHolder, position: Int) { val schedule: Schedule? = getItem(position) holder.date.text = DateFormat.format("yyyy/MM/dd", schedule?.date) holder.title.text = schedule?.title holder.itemView.setOnClickListener { listener?.invoke(schedule?.id) } } override fun getItemId(position: Int): Long { return getItem(position)?.id ?: 0 } }
ScheduleEditActivity.kt
package com.example.myscheduler import android.graphics.Color import androidx.appcompat.app.AppCompatActivity import android.os.Bundle import android.text.format.DateFormat import android.view.View import com.google.android.material.snackbar.Snackbar import io.realm.Realm import io.realm.kotlin.createObject import io.realm.kotlin.where import kotlinx.android.synthetic.main.activity_schedule_edit.* import java.text.ParseException import java.text.SimpleDateFormat import java.util.* class ScheduleEditActivity : AppCompatActivity() { private lateinit var realm: Realm override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_schedule_edit) realm = Realm.getDefaultInstance() val scheduleId = intent?.getLongExtra("schedule_id", -1L) if (scheduleId != -1L) { val schedule = realm.where<Schedule>() .equalTo("id", scheduleId).findFirst() dateEdit.setText(DateFormat.format("yyyy/MM/dd", schedule?.date)) titleEdit.setText(schedule?.title) detailEdit.setText(schedule?.detail) delete.visibility = View.VISIBLE } else { delete.visibility = View.INVISIBLE } save.setOnClickListener { view: View -> when (scheduleId) { -1L -> { realm.executeTransaction { db: Realm -> val maxId = db.where<Schedule>().max("id") val nextId = (maxId?.toLong() ?: 0L) + 1 val schedule = db.createObject<Schedule>(nextId) val date = dateEdit.text.toString().toDate("yyyy/MM/dd") if (date != null) schedule.date = date schedule.title = titleEdit.text.toString() schedule.detail = detailEdit.text.toString() } Snackbar.make(view, "追加しました", Snackbar.LENGTH_SHORT) .setAction("戻る") { finish() } .setActionTextColor(Color.YELLOW) .show() } else -> { realm.executeTransaction { db: Realm -> val schedule = db.where<Schedule>() .equalTo("id", scheduleId).findFirst() val date = dateEdit.text.toString() .toDate("yyyy/MM/dd") if (date != null) schedule?.date = date schedule?.title = titleEdit.text.toString() schedule?.detail = detailEdit.text.toString() } Snackbar.make(view, "修正しました", Snackbar.LENGTH_SHORT) .setAction("戻る") { finish() } .setActionTextColor(Color.YELLOW) .show() } } } delete.setOnClickListener { view: View -> realm.executeTransaction { db: Realm -> db.where<Schedule>().equalTo("id", scheduleId) ?.findFirst() ?.deleteFromRealm() } Snackbar.make(view, "削除しました", Snackbar.LENGTH_SHORT) .setAction("戻る") { finish() } .setActionTextColor(Color.YELLOW) .show() } } override fun onDestroy() { super.onDestroy() realm.close() } private fun String.toDate(pattern: String = "yyyy/MM/dd HH:mm"): Date? { return try { SimpleDateFormat(pattern).parse(this) } catch (e: IllegalArgumentException) { return null } catch (e: ParseException) { return null } } }
試したこと
公式のドキュメントを見たりググったりしましたが、具体的な解決方法が理解できず困っています。解決方法をご教示頂けますと幸いです。
補足情報(FW/ツールのバージョンなど)
・Android Studio 4.1.1
・Kotlin 1.4.20
・io.realm:realm-gradle-plugin 10.0.1
・io.realm:android-adapters 4.0.0
回答1件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2020/12/11 01:05
2020/12/11 01:55
2020/12/11 02:21