Android Realm - Mengakses Objek Realm dari Layanan

Saya memiliki objek ranah yang dibuat dalam aktivitas saya. Saya harus dapat mengakses objek ini dalam layanan yang saya buat. Namun saya mendapatkan kesalahan saat membuat objek Realm dalam layanan

        mRealm = Realm.getInstance(getApplicationContext());

java.lang.IllegalStateException: Akses ranah dari thread yang salah. Objek ranah hanya dapat diakses di thread tempat objek tersebut dibuat

Sekarang saya mengerti ini berarti karena objek realm dibuat pada aktivitas saya, saya tidak dapat mengaksesnya dari thread latar belakang. Namun, saya tidak menemukan cara mudah untuk mengatasi hal ini selain membuat Handler Thread kustom saya sendiri, tetapi itu sepertinya cara yang kikuk untuk melakukannya.

Apakah saya melewatkan sesuatu di sini atau apakah tidak ada cara yang lebih baik untuk dapat mengakses objek Realm dari dalam thread yang berbeda?

Pembaruan:

Saya menggali lebih dalam untuk mengetahui bahwa dalam IntentService, metode onHandleIntent berjalan di thread terpisah dibandingkan metode lain dalam kelas. Oleh karena itu, saya tidak dapat membuat instance Realm tingkat kelas dan dapat berinteraksi dengannya di dalam dan di luar metode onHandleIntent. Itulah yang menyebabkan pengecualian thread. Selain membuat instance Realm terpisah di setiap metode yang saya perlukan untuk mengakses objek dan mengambilnya berulang kali, saya pikir jawaban Ilya Tretyakov akan menjadi yang terbaik. Saya dapat menyalin objek dari dunia nyata di konstruktor saya dan kemudian mengerjakannya sepanjang masa layanan. Metode apa pun yang perlu menulis kembali ke objek Realm perlu membuat instance instance Realmnya sendiri di dalam metode tersebut.


person Landen    schedule 18.02.2016    source sumber
comment
Ini adalah hal yang aneh ketika mereka membatasi sebuah instance pada satu thread. Anda dapat memposting runnable ke aktivitas, dan runnable tersebut akan berjalan di thread aktivitas (Jika Anda masih memiliki akses ke aktivitas tersebut).   -  person Andrew Williamson    schedule 18.02.2016
comment
Cara yang disarankan adalah melakukan query pada layanan yang ada untuk mendapatkan objek yang sama dan menggunakan objek tersebut dalam layanan tersebut. Segalanya akan menjadi sederhana jika objek Anda memiliki kunci utama. Anda dapat melakukan MyObject obj = mRealm.where(MyObject.class).equalTo("id", 123).findFirst(). Saat Anda mengubah obj di layanan, layanan di aktivitas akan diubah secara otomatis di loop UI berikutnya. Anda dapat menggunakan niat untuk meneruskan kunci utama di antara keduanya. Lihat realm.io/docs/java/latest/#threading dan realm.io/docs/java/latest/#intents   -  person beeender    schedule 19.02.2016


Jawaban (2)


Anda dapat mencoba menggunakan realm.copyFromRealm(youRealmObject);. Metode ini menyalin data Realm ke objek Java normal dan melepaskannya dari Realm.

Berikut ini contoh penggunaannya:

youRealmObject = realm.copyFromRealm(youRealmObject);

Berikut informasinya dari dokumen:

Membuat salinan dalam memori mandiri dari RealmObject yang sudah ada. Ini adalah salinan mendalam yang akan menyalin semua objek yang direferensikan. Objek yang disalin semuanya terlepas dari Realm sehingga tidak lagi diperbarui secara otomatis. Artinya, objek yang disalin mungkin berisi data yang tidak lagi konsisten dengan objek Realm terkelola lainnya. PERINGATAN: Setiap perubahan pada objek yang disalin dapat digabungkan kembali ke Realm menggunakan copyToRealmOrUpdate(RealmObject), tetapi semua bidang akan diganti, bukan hanya bidang yang diubah. Ini termasuk referensi ke objek lain, dan berpotensi mengesampingkan perubahan yang dibuat oleh thread lain.

https://realm.io/docs/java/latest/api/io/realm/Realm.html#copyFromRealm-E-

person Ilya Tretyakov    schedule 19.02.2016

Secara teknis Anda seharusnya membuka instance Realm di awal thread latar belakang, menutupnya di akhir eksekusi di latar belakang itu, dan meneruskannya ke metode di antaranya.

public void handleIntent() { // or doInBackground etc
    Realm realm = null;
    try {
         realm = Realm.getDefaultInstance();
         .... 
         MyObj obj = realm.where(MyObj.class)
                          .equalTo(MyObjFields.ID, myObjId)
                          .findFirst(); // get by id
         .... 
    } finally {
         if(realm != null) {
              realm.close(); // important 
         } 
    } 
} 

Menggunakan realm.copyFromRealm() adalah solusi, bukan solusi.


Dengan AS 3.0, Anda sebenarnya dapat menggunakan try-with-resources apa pun minSDK Anda (sama seperti jika Anda menggunakan Retrolambda):

public void handleIntent() { // or doInBackground etc
    try(Realm realm = Realm.getDefaultInstance()) {
         .... 
         MyObj obj = realm.where(MyObj.class)
                          .equalTo(MyObjFields.ID, myObjId)
                          .findFirst(); // get by id
         .... 
    } // auto-close
} 
person EpicPandaForce    schedule 27.10.2016
comment
Terima kasih telah menyebutkan tip try-with-resources. Saya tidak mengetahui fitur ini di AS 3 - person Nicolás Carrasco-Stevenson; 20.06.2018