Android Realm - การเข้าถึงวัตถุ Realm จากบริการ

ฉันมีวัตถุอาณาจักรที่สร้างขึ้นในกิจกรรมของฉัน ฉันต้องสามารถเข้าถึงออบเจ็กต์นี้ภายในบริการที่ฉันสร้างขึ้นได้ อย่างไรก็ตาม ฉันได้รับข้อผิดพลาดเมื่อสร้างวัตถุ Realm ภายในบริการ

        mRealm = Realm.getInstance(getApplicationContext());

java.lang.IllegalStateException: การเข้าถึงขอบเขตจากเธรดที่ไม่ถูกต้อง วัตถุขอบเขตสามารถเข้าถึงได้บนเธรดที่สร้างขึ้นเท่านั้น

ตอนนี้ฉันเข้าใจแล้วว่าเนื่องจากวัตถุอาณาจักรถูกสร้างขึ้นในกิจกรรมของฉัน ฉันไม่สามารถเข้าถึงได้จากเธรดพื้นหลัง อย่างไรก็ตาม ฉันไม่ได้พบวิธีง่ายๆ ในการทำเช่นนี้นอกเหนือจากการสร้าง Handler Thread แบบกำหนดเองของฉันเอง แต่นั่นดูเหมือนจะเป็นวิธีที่ยุ่งยากในการทำ

ฉันขาดอะไรบางอย่างที่นี่หรือไม่มีวิธีใดที่จะดีไปกว่านี้ในการเข้าถึงวัตถุ Realm จากภายในเธรดต่างๆ

อัปเดต:

ฉันเจาะลึกลงไปอีกเล็กน้อยเพื่อดูว่าใน IntentService เมธอด onHandleIntent ทำงานในเธรดที่แยกจากวิธีอื่นภายในคลาส ดังนั้นฉันจึงไม่สามารถสร้างอินสแตนซ์ Realm ระดับคลาสได้และสามารถโต้ตอบกับสิ่งนั้นทั้งภายในและภายนอกเมธอด onHandleIntent ได้ นั่นคือสิ่งที่ทำให้เกิดข้อยกเว้นของเธรด นอกเหนือจากการสร้าง Realm แยกกันในแต่ละวิธีที่ฉันต้องเข้าถึงวัตถุและเรียกค้นมันซ้ำแล้วซ้ำเล่า ฉันคิดว่าคำตอบของ Ilya Tretyakov จะดีที่สุด ฉันสามารถคัดลอกอ็อบเจ็กต์จากขอบเขตในตัวสร้างของฉัน จากนั้นจึงทำงานกับวัตถุนั้นได้ตลอดอายุของบริการ วิธีการใดๆ ที่ต้องเขียนกลับไปยังออบเจ็กต์ Realm จะต้องสร้างอินสแตนซ์ Realm ของตนเองภายในวิธีการนั้น


person Landen    schedule 18.02.2016    source แหล่งที่มา
comment
เป็นเรื่องที่น่าอึดอัดใจเมื่อพวกเขาจำกัดอินสแตนซ์ไว้ที่เธรดเดียว คุณสามารถโพสต์ runable ไปยังกิจกรรมได้ และมันจะรันบนเธรดกิจกรรม (หากคุณยังสามารถเข้าถึงกิจกรรมได้)   -  person Andrew Williamson    schedule 18.02.2016
comment
วิธีที่แนะนำคือทำแบบสอบถามในบริการนั้นเพื่อรับวัตถุเดียวกันและใช้วัตถุนั้นในบริการ สิ่งต่างๆ จะเป็นเรื่องง่ายหากวัตถุของคุณมีคีย์หลัก คุณก็ทำได้MyObject obj = mRealm.where(MyObject.class).equalTo("id", 123).findFirst() เมื่อคุณเปลี่ยน obj ในบริการ กิจกรรมในกิจกรรมจะถูกเปลี่ยนโดยอัตโนมัติในวง UI ถัดไป คุณสามารถใช้ความตั้งใจในการส่งคีย์หลักระหว่างกัน ดู realm.io/docs/java/latest/#threading และ realm.io/docs/java/latest/#intents   -  person beeender    schedule 19.02.2016


คำตอบ (2)


คุณสามารถลองใช้ realm.copyFromRealm(youRealmObject); วิธีการเหล่านี้จะคัดลอกข้อมูล Realm ลงในออบเจ็กต์ Java ปกติและแยกออกจาก Realm

นี่คือตัวอย่างการใช้งาน:

youRealmObject = realm.copyFromRealm(youRealmObject);

นี่คือข้อมูลเกี่ยวกับเรื่องนี้จากเอกสาร:

สร้างสำเนาในหน่วยความจำแบบสแตนด์อโลนของ RealmObject ที่เก็บไว้แล้ว นี่เป็นสำเนาเชิงลึกที่จะคัดลอกออบเจ็กต์ที่อ้างอิงทั้งหมด ออบเจ็กต์ที่คัดลอกทั้งหมดจะถูกแยกออกจาก Realm ดังนั้นจึงจะไม่ได้รับการอัปเดตโดยอัตโนมัติอีกต่อไป ซึ่งหมายความว่าออบเจ็กต์ที่คัดลอกอาจมีข้อมูลที่ไม่สอดคล้องกับออบเจ็กต์ Realm ที่ได้รับการจัดการอื่นๆ อีกต่อไป คำเตือน: การเปลี่ยนแปลงใดๆ ในออบเจ็กต์ที่คัดลอกสามารถรวมกลับเข้าไปใน Realm ได้โดยใช้ copyToRealmOrUpdate(RealmObject) แต่ช่องทั้งหมดจะถูกแทนที่ ไม่ใช่แค่ช่องที่มีการเปลี่ยนแปลงเท่านั้น ซึ่งรวมถึงการอ้างอิงถึงออบเจ็กต์อื่น และอาจแทนที่การเปลี่ยนแปลงที่ทำโดยเธรดอื่นได้

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

person Ilya Tretyakov    schedule 19.02.2016

ในทางเทคนิคแล้ว คุณควรเปิดอินสแตนซ์ Realm ที่จุดเริ่มต้นของเธรดพื้นหลัง ปิดอินสแตนซ์ดังกล่าวเมื่อสิ้นสุดการดำเนินการในพื้นหลังนั้น แล้วส่งต่อไปยังวิธีการในระหว่างนั้น

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 
         } 
    } 
} 

การใช้ realm.copyFromRealm() เป็นเพียงวิธีแก้ปัญหา ไม่ใช่วิธีแก้ปัญหา


ด้วย AS 3.0 คุณสามารถใช้ try-with-resources ได้จริงไม่ว่า minSDK ของคุณจะเป็นอย่างไรก็ตาม (เช่นเดียวกับที่คุณใช้ 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
ขอขอบคุณที่กล่าวถึงเคล็ดลับ try-with-resources ฉันไม่ทราบถึงฟีเจอร์นี้ใน AS 3 - person Nicolás Carrasco-Stevenson; 20.06.2018