2016-02-26 8 views
12

मेरे Android परियोजनाओं में, मैं अपने डेटा भंडारण इंजन के रूप में realm का उपयोग करें। मुझे यह पसंद है!
मैं भी RxJava उपयोग करें, क्योंकि यह "सूत्रण" बनाता है इतना आसान है, और मैं सच में पूरे "प्रतिक्रियाशील मानसिकता" की तरह। मुझे यह पसंद है!
क्षेत्र, RxJava, asObservable() और doOnUnsubscribe()

मैं एक एमवीपी पैटर्न + कुछ "स्वच्छ वास्तुकला" विचारों का उपयोग अपने एप्लिकेशन बनाने के लिए।

मेरा Interactors केवल Realm के बारे में पता है। मैं प्रत्यक्ष की मदद से डेटा का पर्दाफाश, इस तरह:

@Override 
public Observable<City> getHomeTown() { 
    final Realm realm = Realm.getDefaultInstance(); 
    return realm.where(City.class).equalTo("name", "Cluj-Napoca").findAllAsync().asObservable() 
      .doOnUnsubscribe(new Action0() { 
       @Override 
       public void call() { 
        realm.close(); 
       } 
      }) 
      .compose(new NullIfNoRealmObject<City>()); 
} 

समस्या है, मेरी doOnUnsubscribe पक्ष प्रभाव Realm से पहले कहा जाता हो जाता है अपनी बात कर सकते हैं निपटने उजागर नमूदार:

Caused by: java.lang.IllegalStateException: This Realm instance has already been closed, making it unusable. 
at io.realm.BaseRealm.checkIfValid(BaseRealm.java:344) 
at io.realm.RealmResults.removeChangeListener(RealmResults.java:818) 
at io.realm.rx.RealmObservableFactory$3$2.call(RealmObservableFactory.java:137) 
at rx.subscriptions.BooleanSubscription.unsubscribe(BooleanSubscription.java:71) 
at rx.internal.util.SubscriptionList.unsubscribeFromAll(SubscriptionList.java:124) 
at rx.internal.util.SubscriptionList.unsubscribe(SubscriptionList.java:113) 
at rx.Subscriber.unsubscribe(Subscriber.java:98) 
at rx.internal.util.SubscriptionList.unsubscribeFromAll(SubscriptionList.java:124) 
at rx.internal.util.SubscriptionList.unsubscribe(SubscriptionList.java:113) 
at rx.Subscriber.unsubscribe(Subscriber.java:98) 
at rx.subscriptions.CompositeSubscription.unsubscribeFromAll(CompositeSubscription.java:150) 
at rx.subscriptions.CompositeSubscription.unsubscribe(CompositeSubscription.java:139) 
at ro.tudorluca.realm.sandbox.city.CityPresenter.onDestroy(CityPresenter.java:62) 
at ro.tudorluca.realm.sandbox.city.CityActivity.onDestroy(CityActivity.java:35) 

मेरे द्वारा बनाए गए उपयोग के इस मामले एक sandbox परियोजना।

मुझे वास्तव में रीयलम + आरएक्सजेवा का उपयोग करना पसंद है, लेकिन मुझे close का वास्तविक समाधान प्रतीत नहीं होता है जब मैं unsubscribe (जब आमतौर पर गतिविधि नष्ट हो जाती है तो मैं सदस्यता छोड़ता हूं)। कोई विचार?

संपादित करें 1: https://github.com/realm/realm-java/issues/2357
संपादित 2: बहुत सक्रिय दायरे टीम के लिए धन्यवाद, वहाँ पहले से ही एक pull request इस समस्या को हल करने के लिए है।

उत्तर

1

21 घंटे बाद और यह है कि क्या मैं के साथ आया है।

flatMap() के विपरीत, concatMap() उत्सर्जन के आदेश रखना होगा जो, मेरे मामले में, इसका मतलब है कि मेरी Action0 -> realm.close() अंतिम क्रिया धारा से सदस्यता समाप्ति के बाद बुलाया जा रहा है, क्षेत्र के Action0 -> results.removeChangeListener(listener) जो समस्या पैदा कर रहा था के बाद किया जाएगा।

एक पूर्ण उदाहरण github पर पाया जा सकता है।

संपादित करें: बहुत सक्रिय क्षेत्र टीम के लिए धन्यवाद, इस समस्या को ठीक करने के लिए पहले से ही pull request है।

+0

अवलोकन करने योग्य # के माध्यम से दायरे को लपेटने पर विचार करें, यह आपके getManagedRealm() विधि को सरल बना देगा: http://pastebin.com/CrzryvCq –

+0

मैं आपके समाधान का प्रयास करता हूं और मुझे समस्या का सामना करना पड़ता है: वास्तविक फ़ाइल में बहुत अधिक खुले –

0

जब से तुम ने कहा कि केवल Interactor "जानता" क्षेत्र ढांचे के बारे में मैं कहूंगा कि यहां तक ​​कि एक कामयाब क्षेत्र वस्तु न लौटने की बजाय copyFromRealm का उपयोग कर परिणामों के एक अप्रबंधित प्रतिलिपि लौट आते हैं। इस तरह आप की जरूरत नहीं है क्षेत्र उदाहरण खुले या प्रस्तुतकर्ता में बंद कर दिया जा रहा है के बारे में देखभाल करने के लिए।

मैं होगा एक ही समय में प्रस्तुतकर्ता चुना है मौसम कॉल अतुल्यकालिक या नहीं के बाद से RxJava कि बहुत अच्छा और आसान करता है और आप एक और धागा भीतर Interactor लोड विधि बुला मुद्दों की ज़रूरत नहीं होगी किया जाना चाहिए (जो Loopers का उपयोग कर बचा जा सकता है लेकिन यदि आप इसे आसान बनाने के कर सकते हैं क्यों स्थिति overcomplicate: पी)।

तो मैं जाना के लिए होगा:

Override 
public Observable<City> getHomeTown() { 
    final Realm realm = Realm.getDefaultInstance(); 
    City city = realm.where(City.class).equalTo("name", "Cluj-Napoca").findFirst(); 

    // make sure we don't send back Realm stuff, this is a deep copy that will copy all referenced objects (as the method doc says) 
    City cityUnmanaged = realm.copyFromRealm(city); 

    // safe to close the realm instance now 
    realm.close(); 

    return Observable.just(cityUnmanaged); 
} 

मैं और अधिक विकल्प देखने के लिए उत्सुक हूँ :)।

@Override 
public Observable<City> getHomeTown() { 
    return getManagedRealm() 
      .concatMap(new Func1<Realm, Observable<City>>() { 
       @Override 
       public Observable<City> call(Realm realm) { 
        return realm.where(City.class).equalTo("name", "Cluj-Napoca").findAllAsync().asObservable() 
          .compose(new NullIfNoRealmObject<City>()); 
       } 
      }); 
} 

private static Observable<Realm> getManagedRealm() { 
    return Observable.create(new Observable.OnSubscribe<Realm>() { 
     @Override 
     public void call(final Subscriber<? super Realm> subscriber) { 
      final Realm realm = Realm.getDefaultInstance(); 
      subscriber.add(Subscriptions.create(new Action0() { 
       @Override 
       public void call() { 
        realm.close(); 
       } 
      })); 
      subscriber.onNext(realm); 
     } 
    }); 
} 

मैं stackoverflow पर प्रश्न पोस्ट करने से पहले कुछ इस तरह की कोशिश की, लेकिन मेरी गलती concatMap() के बजाय flatMap() उपयोग कर रहा था,:

+1

एक पर्यवेक्षक लौट रहा है, मेरा इंटरैक्टर पूरी तरह से "प्रतिक्रियाशील मानसिकता" को गले लगाता है। जब आप क्वेरी निष्पादित करते हैं, तो इंटरैक्टर एक स्ट्रीम लौटाएगा जो डेटा तैयार और उपलब्ध होने पर पुश करेगा। जब नया डेटा उपलब्ध होता है, तो लौटाई गई धारा आपको उस डेटा को धक्का देने के लिए तैयार होती है। मेरे मामले में, जब भी किसी और ने क्षेत्र में परिवर्तन को धक्का दिया तो मुझे एक अद्यतन शहर मिलेगा। "ऑटो-रीफ्रेश" दायरे की मुख्य विशेषता है, और एक बहुत अच्छा है। –

+0

इसके अलावा, copyFromRealm() मेरे डेमो के लिए ठीक है, क्योंकि मेरी वस्तुएं कोई संबंध नहीं हैं। लेकिन वास्तविक जीवन में, मेरे पास वस्तुओं का एक जटिल ग्राफ है और मैं वास्तव में उन्हें सभी को स्मृति में लोड नहीं करना चाहता हूं। "आलसी + नो-कॉपी डेटा" दायरे की एक और मुख्य विशेषता है कि जब भी आप कर सकते हैं, आपको पूर्ण लाभ लेना चाहिए। –

+0

दायरे में "थ्रेडिंग" सीमा है और आप बहु-थ्रेडेड प्रश्नों को संभालने के लिए आरएक्सजेवा का उपयोग नहीं कर सकते हैं। एक अच्छी उदाहरण परियोजना है जिसे आप अधिक गॉथस के लिए खोज सकते हैं: https://github.com/realm/realm-java/blob/master/examples/rxJavaExample/src/main/java/io/realm/examples/rxjava/gotchas /GotchasActivity.java –

0

मेरे अनुसार, एक अच्छी वास्तुकला में देखभाल करने वाली प्रमुख चीज़ों में से एक मॉड्यूलरिटी है। सभी प्रमुख मॉड्यूल (या पुस्तकालय) को शेष कोड से अलग किया जाना चाहिए। चूंकि दायरे, RealmObject या RealmResult धागे में पारित नहीं किया जा सकता है, इसलिए रीयल & रीयल से संबंधित संचालन को कोड के बाकी हिस्सों से अलग करना भी महत्वपूर्ण है।

इस दर्शन को ध्यान में रखते हुए, मैं निम्नलिखित दृष्टिकोण के साथ आया।

प्रत्येक जेसन मॉडल श्रेणी के लिए, हम एक वास्तविक मॉडल श्रेणी और एक डीएओ (डेटा एक्सेस ऑब्जेक्ट) कक्षा बनाते हैं। यहां विचार यह है कि डीएओ कक्षा के अलावा किसी भी वर्ग को रीयलम मॉडल या दायरे इकाइयों को जानना या एक्सेस करना चाहिए। डीएओ क्लास जेसन मॉडेल लेता है, इसे रीयलम मॉडेल में परिवर्तित करता है, पढ़ने के लिए पढ़ने/लिखने/संपादित/हटाता है & पढ़ने के लिए डीएओ परिवर्तित होता है जिसके परिणामस्वरूप realmModel को jsonModel में बदल दिया जाता है और उन्हें वापस कर देता है।

इस तरह से क्षेत्र को बनाए रखना आसान है, सभी धागे से संबंधित मुद्दों से बचें, परीक्षण करने और डीबग करने में आसान है।

यहाँ एक अच्छा वास्तुकला https://medium.com/@Viraj.Tank/realm-integration-in-android-best-practices-449919d25f2f

साथ क्षेत्र सर्वोत्तम प्रथाओं के बारे में एक लेख है इसके अलावा एक नमूना परियोजना एमवीपी (मॉडल देखें प्रस्तुतकर्ता), RxJava, रेट्रोफिट, डैगर, एनोटेशन & परीक्षण के साथ Android पर क्षेत्र की एकता का प्रदर्शन है। https://github.com/viraj49/Realm_android-injection-rx-test