質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.69%
Realm

RealmとはSQLiteやCore Dataに代わるモバイルデータベースです。iOSとAndroidの両方でサポートされています。

Android

Androidは、Google社が開発したスマートフォンやタブレットなど携帯端末向けのプラットフォームです。 カーネル・ミドルウェア・ユーザーインターフェイス・ウェブブラウザ・電話帳などのアプリケーションやソフトウェアをひとつにまとめて構成。 カーネル・ライブラリ・ランタイムはほとんどがC言語/C++、アプリケーションなどはJavaSEのサブセットとAndroid環境で書かれています。

Kotlin

Kotlinは、ジェットブレインズ社のアンドリー・ブレスラフ、ドミトリー・ジェメロフが開発した、 静的型付けのオブジェクト指向プログラミング言語です。

Q&A

解決済

1回答

9559閲覧

Realmを7.0.8から10.0.1に変更するとio.realm.exceptions.RealmExceptionが発生してアプリがクラッシュする

tcrt56

総合スコア1

Realm

RealmとはSQLiteやCore Dataに代わるモバイルデータベースです。iOSとAndroidの両方でサポートされています。

Android

Androidは、Google社が開発したスマートフォンやタブレットなど携帯端末向けのプラットフォームです。 カーネル・ミドルウェア・ユーザーインターフェイス・ウェブブラウザ・電話帳などのアプリケーションやソフトウェアをひとつにまとめて構成。 カーネル・ライブラリ・ランタイムはほとんどがC言語/C++、アプリケーションなどはJavaSEのサブセットとAndroid環境で書かれています。

Kotlin

Kotlinは、ジェットブレインズ社のアンドリー・ブレスラフ、ドミトリー・ジェメロフが開発した、 静的型付けのオブジェクト指向プログラミング言語です。

0グッド

0クリップ

投稿2020/12/10 04:18

前提・実現したいこと

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

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

下記のような質問は推奨されていません。

  • 質問になっていない投稿
  • スパムや攻撃的な表現を用いた投稿

適切な質問に修正を依頼しましょう。

また依頼した内容が修正された場合は、修正依頼を取り消すようにしましょう。

guest

回答1

0

ベストアンサー

このメッセージを読むとUIスレッドでトランザクション処理はできないと読めるので、

Running transactions on the UI thread has been disabled. It can be enabled by setting 'RealmConfiguration.Builder.allowWritesOnUiThread(true)'.

こういう箇所は全部UIスレッド以外でやると解決しそうです。

realm.executeTransaction

Realmを使用したことがないのではっきりとは分からないのですが、executeTransactionではなく、何か似たような名前で別スレッドでやる専用のメソッドが用意されていればそれを使っても解決できそうですし、なさそうであればKotlinのコルーチンでwithContext(Dispatchers.IO)あたりを駆使すれば解決できそうに見えます。
UIスレッドでどうしてもしたい場合は、エラーメッセージを見ると
RealmConfiguration.Builder.allowWritesOnUiThread(true)
これを事前に設定するとUIスレッドでもできるようになるみたいですが、
Databaseの読み書きをUIスレッドで行うのは一般的に好ましくないと思いますので、
ちゃんとやるならUIスレッド以外でやる方が良いと思います。

投稿2020/12/10 08:56

Sagamaru

総合スコア70

下記のような回答は推奨されていません。

  • 質問の回答になっていない投稿
  • スパムや攻撃的な表現を用いた投稿

このような回答には修正を依頼しましょう。

また依頼した内容が修正された場合は、修正依頼を取り消すようにしましょう。

回答へのコメント

tcrt56

2020/12/11 01:05

お返事頂きありがとうございます。ネット上にあるSampleコードを眺めてみましたが、executeTransactionに代わるメソッドがなかなか見つかりません。そもそも、古いバージョンのRealmを使っているものが多いです。公式のドキュメントを含め、もう少し情報が整ってからバージョンを上げるべきなのかもしれませんね。
Sagamaru

2020/12/11 01:55

公式サイト見ると https://realm.io/docs/java/latest/ それっぽいのはいますね。 executeTransactionAsync Kotlinではなくて、Javaのサンプルになりますが 「background thread」というコメントもあるのでもしかするといけるかもしれません。 / /Asynchronously update objects on a background thread realm.executeTransactionAsync(new Realm.Transaction() { @Override public void execute(Realm bgRealm) { Dog dog = bgRealm.where(Dog.class).equalTo("age", 1).findFirst(); dog.setAge(3); } }, new Realm.Transaction.OnSuccess() { @Override public void onSuccess() { // Original queries and Realm objects are automatically updated. puppies.size(); // => 0 because there are no more puppies younger than 2 years old managedDog.getAge(); // => 3 the dogs age is updated } });
tcrt56

2020/12/11 02:21

教えて頂いた通りexecuteTransactionをexecuteTransactionAsyncに変えたところ正常に動きました。Kotlinのドキュメントしか見ていなかったので盲点でした。お付き合い頂いてありがとうございました。感謝致します。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.69%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

同じタグがついた質問を見る

Realm

RealmとはSQLiteやCore Dataに代わるモバイルデータベースです。iOSとAndroidの両方でサポートされています。

Android

Androidは、Google社が開発したスマートフォンやタブレットなど携帯端末向けのプラットフォームです。 カーネル・ミドルウェア・ユーザーインターフェイス・ウェブブラウザ・電話帳などのアプリケーションやソフトウェアをひとつにまとめて構成。 カーネル・ライブラリ・ランタイムはほとんどがC言語/C++、アプリケーションなどはJavaSEのサブセットとAndroid環境で書かれています。

Kotlin

Kotlinは、ジェットブレインズ社のアンドリー・ブレスラフ、ドミトリー・ジェメロフが開発した、 静的型付けのオブジェクト指向プログラミング言語です。