सदस्यता के परिणाम का उपयोग नहीं किया जाता है


133

मैंने आज एंड्रॉइड स्टूडियो 3.1 में अपग्रेड किया है, जो लगता है कि कुछ और लिंट चेक जोड़े गए हैं। इनमें से एक लिंट चेक एक-शॉट RxJava2 subscribe()कॉल के लिए है जो एक चर में संग्रहीत नहीं है। उदाहरण के लिए, मेरे कक्ष डेटाबेस से सभी खिलाड़ियों की सूची प्राप्त करना:

Single.just(db)
            .subscribeOn(Schedulers.io())
            .subscribe(db -> db.playerDao().getAll());

एक बड़े पीले ब्लॉक और इस टूलटिप में परिणाम:

के परिणाम का subscribeउपयोग नहीं किया जाता है

एंड्रॉइड स्टूडियो का स्क्रीनशॉट।  कोड को पीले में टूलटिप के साथ हाइलाइट किया गया है।  टूलटिप पाठ: सदस्यता के परिणाम का उपयोग नहीं किया जाता है।

इस तरह से एक-शॉट आरएक्स कॉल के लिए सबसे अच्छा अभ्यास क्या है? मैं की पकड़ रखना चाहिए Disposableऔर dispose()पूरा पर? या मैं बस @SuppressLintऔर आगे बढ़ना चाहिए ?

यह केवल RxJava2 ( io.reactivex) को प्रभावित rxकरता है , RxJava ( ) के पास यह लिंट नहीं है।


आपके दोनों समाधानों में, मुझे ईमानदारी से लगता है कि @SuppressLint सबसे अच्छा नहीं है। शायद मैं गलत हूं, लेकिन मुझे लगता है कि कोड को आईडीई चेतावनियों और / या संकेत को कभी नहीं बदलना चाहिए
आर्थर एटाउट

@ArthurAttout सहमत हैं, वर्तमान में मैं Disposableसदस्य के दायरे में पकड़ बना रहा हूं और dispose()जब कॉल पूरा हो जाता है, लेकिन यह अनावश्यक रूप से बोझिल लगता है। मुझे यह देखने में दिलचस्पी है कि क्या ऐसा करने के कोई बेहतर तरीके हैं।
माइकल डोड

8
मुझे लगता है कि RxJava स्ट्रीम सब्सक्राइब / फ्रैगमेंट / व्यूमॉडल के भीतर से सब्सक्राइब नहीं होने पर यह लिंट चेतावनी कष्टप्रद है। मेरे पास एक कंप्लीटटेबल है जो गतिविधि जीवन चक्र के लिए किसी भी संबंध के बिना सुरक्षित रूप से चल सकता है, फिर भी मुझे अभी भी इसे निपटाने की आवश्यकता है?
EM

RxLifecycle पर विचार
최봉재

जवाबों:


122

आईडीई को यह नहीं पता है कि आपकी सदस्यता के संभावित प्रभाव क्या हो सकते हैं जब इसे निपटाया नहीं जाता है, इसलिए यह इसे संभावित असुरक्षित मानता है। उदाहरण के लिए, आपके Singleनेटवर्क में एक नेटवर्क कॉल हो सकती है, जो आपके Activityनिष्पादन के दौरान छोड़ दिए जाने पर स्मृति रिसाव का कारण बन सकती है ।

एक बड़ी मात्रा का प्रबंधन करने के लिए एक सुविधाजनक तरीका Disposableएक सम्मिश्र उपयोग करना है ; बस CompositeDisposableअपने एन्कोडिंग वर्ग में एक नया इंस्टेंस वेरिएबल बनाएं , फिर अपने सभी डिस्पोज़ेबल्स को कम्पोजिटडिस्पोजेबल में जोड़ें (RxKotlin के साथ आप बस अपने सभी डिस्पोज़ेबल्स के लिए अपील कर सकते हैं addTo(compositeDisposable))। अंत में, जब आप अपने उदाहरण के साथ काम करते हैं, तो कॉल करें compositeDisposable.dispose()

यह एक प्रकार का वृक्ष चेतावनी से छुटकारा दिलाएगा, और यह सुनिश्चित करेगा कि आपका Disposablesप्रबंधन ठीक से किया जाए।

इस स्थिति में, कोड इस तरह दिखेगा:

CompositeDisposable compositeDisposable = new CompositeDisposable();

Disposable disposable = Single.just(db)
        .subscribeOn(Schedulers.io())
        .subscribe(db -> db.get(1)));

compositeDisposable.add(disposable); //IDE is satisfied that the Disposable is being managed. 
disposable.addTo(compositeDisposable); //Alternatively, use this RxKotlin extension function.


compositeDisposable.dispose(); //Placed wherever we'd like to dispose our Disposables (i.e. in onDestroy()).

मुझे error: cannot find symbol method addTo(CompositeDisposable)"rxjava: 2.1.13" के साथ संकलित त्रुटि मिल रही है । यह विधि कहाँ से आती है? (RxSwift या RxKotlin I suppose)
एरैकोड

2
हाँ, यह एक RxKotlin विधि है।
अत्यावश्यक

1
प्रवाह के मामले में क्या करना है
हंट

क्या होगा अगर हम doOnSubscribe में कर रहे हैं
किलर

2
यह एक स्मृति रिसाव का कारण नहीं होगा। एक बार जब नेटवर्क कॉल खत्म हो जाता है और ऑनकॉम पूरा हो जाता है, तो कचरा संग्रह बाकी के साथ तब तक निपटेगा जब तक कि आपने डिस्पोजेबल का स्पष्ट संदर्भ नहीं रखा हो और इसे डिस्पोज न करें।
गेब्रियल वास्कोनसेलोस

26

जिस क्षण गतिविधि नष्ट हो जाएगी, डिस्पोज़ेबल्स की सूची साफ़ हो जाती है और हम अच्छे हो जाते हैं।

io.reactivex.disposables.CompositeDisposable mDisposable;

    mDisposable = new CompositeDisposable();

    mDisposable.add(
            Single.just(db)
                    .subscribeOn(Schedulers.io())
                    .subscribe(db -> db.get(1)));

    mDisposable.dispose(); // dispose wherever is required

9

आप DisposableSingleObserver के साथ सदस्यता ले सकते हैं :

Single.just(db)
    .subscribeOn(Schedulers.io())
    .subscribe(new DisposableSingleObserver<Object>() {
            @Override
            public void onSuccess(Object obj) {
                // work with the resulting todos...
                dispose();
            }

            @Override
            public void onError(Throwable e) {
                // handle the error case...
                dispose();
            }});

मामले में आपको Singleऑब्जेक्ट को सीधे निपटाने की आवश्यकता होती है (जैसे कि उत्सर्जन से पहले) आप संदर्भ onSubscribe(Disposable d)प्राप्त करने और उपयोग करने के लिए विधि को लागू कर सकते हैं Disposable

आप SingleObserverस्वयं भी इंटरफ़ेस का एहसास कर सकते हैं या अन्य बाल वर्गों का उपयोग कर सकते हैं।


5

जैसा कि सुझाव दिया गया था कि आप CompositeDisposableवहां सदस्यता अभियान के परिणाम को जोड़ने के लिए कुछ वैश्विक का उपयोग कर सकते हैं ।

RxJava2Extensions पुस्तकालय के लिए स्वचालित रूप से से डिस्पोजेबल बनाया निकाल उपयोगी तरीकों में शामिल है CompositeDisposable, जब यह पूरा करता है। सब्सक्राइब करें अनुभाग देखें

आपके मामले में ऐसा लग सकता है

SingleConsumers.subscribeAutoDispose(
    Single.just(db)
            .subscribeOn(Schedulers.io()),
    composite,
    db -> db.playerDao().getAll())

2

आप Uber AutoDispose और rxjava का उपयोग कर सकते हैं.as

        Single.just(db)
            .subscribeOn(Schedulers.io())
            .as(AutoDispose.autoDisposable(AndroidLifecycleScopeProvider.from(this)))
            .subscribe(db -> db.playerDao().getAll());

सुनिश्चित करें कि जब आप स्कोपप्रोविडर के आधार पर सदस्यता समाप्त करते हैं, तो आप इसे समझें।


यह मानता है कि एक जीवनचक्र प्रदाता उपलब्ध है। इसके अलावा, "के रूप में" विधि अस्थिर के रूप में चिह्नित है, इसलिए इसका उपयोग करने से एक लिंट चेतावनी मिलेगी।
डब्बलर

1
धन्यवाद @ डब्लर, सहमत। .As विधि RxJava 2.1.7 जब तक प्रयोगात्मक था और 2.2 पर यह स्थिर।
ब्लफी

1

बार-बार मैं खुद को इस सवाल पर वापस आ रहा हूं कि सदस्यता के सही तरीके से निपटान कैसे करें, और विशेष रूप से इस पोस्टिंग के लिए। कई ब्लॉग और बातचीत का दावा है कि कॉल करने में विफल रहने से disposeमेमोरी लीक हो जाती है, जो मुझे लगता है कि बहुत सामान्य कथन है। मेरी समझ में, परिणाम के बारे में नहीं बताने के बारे में एक चेतावनी subscribeकुछ मामलों में एक गैर-मुद्दा है, क्योंकि:

  • सभी वेधशालाएं Android गतिविधि के संदर्भ में नहीं चलती हैं
  • अवलोकनीय समकालिक हो सकता है
  • निपटाने को अंतर्निहित रूप से कहा जाता है, बशर्ते कि अवलोकन योग्य पूर्णता हो

चूँकि मैं हाल ही में एक तुल्यकालिक अवलोकन के साथ मामलों के लिए निम्नलिखित पैटर्न का उपयोग करना शुरू करने के लिए एक प्रकार का वृक्ष चेतावनी को दबाना नहीं चाहता:

var disposable: Disposable? = null

disposable = Observable
   .just(/* Whatever */)
   .anyOperator()
   .anyOtherOperator()
   .subscribe(
      { /* onSuccess */ },
      { /* onError */ },
      {
         // onComplete
         // Make lint happy. It's already disposed because the stream completed.
         disposable?.dispose()
      }
   )

मुझे इस पर किसी भी टिप्पणी में दिलचस्पी होगी, भले ही यह शुद्धता की पुष्टि हो या लूपहोल की खोज।


0

एक और तरीका उपलब्ध है, जो मैन्युअल रूप से डिस्पोज़ेबल्स का उपयोग करने से बच रहा है (सब्सक्रिप्शन जोड़ें और हटाएं)।

तुम एक परिभाषित कर सकते हैं प्रत्यक्ष और उस नमूदार एक से संदेश प्राप्त करने जा रहा है SubjectBehaviour (आप RxJava का उपयोग मामले में)। और अपने LiveData के लिए उस अवलोकन को पारित करके , उसे काम करना चाहिए। प्रारंभिक प्रश्न के आधार पर अगला उदाहरण देखें:

private val playerSubject: Subject<Player> = BehaviorSubject.create()

private fun getPlayer(idPlayer: String) {
        playerSubject.onNext(idPlayer)
}

private val playerSuccessful: Observable<DataResult<Player>> = playerSubject
                        .flatMap { playerId ->
                            playerRepository.getPlayer(playerId).toObservable()
                        }
                        .share()

val playerFound: LiveData<Player>
    get() = playerSuccessful
        .filterAndMapDataSuccess()
        .toLiveData()

val playerNotFound: LiveData<Unit>
    get() = playerSuccessful.filterAndMapDataFailure()
        .map { Unit }
        .toLiveData()

// These are a couple of helpful extensions

fun <T> Observable<DataResult<T>>.filterAndMapDataSuccess(): Observable<T> =
filter { it is DataResult.Success }.map { (it as DataResult.Success).data }

fun <T> Observable<DataResult<T>>.filterAndMapDataFailure(): Observable<DataResult.Failure<T>> =
filter { it is DataResult.Failure }.map { it as DataResult.Failure<T> }

-10

यदि आपको यकीन है कि डिस्पोजेबल को सही तरीके से संभाला जाता है, उदाहरण के लिए doOnSubscribe () ऑपरेटर का उपयोग करके, आप इसे ग्रेड में जोड़ सकते हैं:

android {
lintOptions {
     disable 'CheckResult'
}}

10
यह अनियंत्रित परिणाम के सभी उदाहरणों के लिए इस लिंट चेक को दबा देगा। ओपी के उदाहरण के बाहर बहुत बार हैं जिसमें किसी को लौटे परिणाम को संभालना चाहिए। यह एक मक्खी को मारने के लिए एक स्लेजहैमर का उपयोग कर रहा है।
tir38

16
कृपया यह मत करो! एक कारण है कि आपको ये चेतावनी मिल रही है। यदि आप जानते हैं कि आप क्या कर रहे हैं (और जानते हैं कि आपको वास्तव में कभी भी अपनी सदस्यता को निपटाने की आवश्यकता नहीं है) तो आप @SuppressLint("CheckResult")सिर्फ विधि पर दबा सकते हैं ।
विक्टर रेंडिना
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.