Abone olmanın sonucu kullanılmaz


133

Bugün Android Studio 3.1'e yükselttim, bu da birkaç tiftik kontrolü daha ekledi. Bu tiftik kontrollerinden biri subscribe(), bir değişkende depolanmayan tek seferlik RxJava2 çağrıları içindir. Örneğin, Oda veritabanımdan tüm oyuncuların bir listesini almak:

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

Büyük sarı bir blok ve bu ipucu ile sonuçlanır:

Sonucu subscribekullanılmaz

Android Studio'nun ekran görüntüsü.  Kod, bir araç ipucuyla Sarı ile vurgulanır.  Araç ipucu metni: Abone olmanın sonucu kullanılmaz.

Bunun gibi tek seferlik Rx aramaları için en iyi uygulama nedir? Ben bırakmamak mı Disposableve dispose()tam üzerinde? Yoksa sadece @SuppressLintdevam mı etmeliyim ?

Bu sadece RxJava2 ( io.reactivex) ' yi etkiliyor gibi görünüyor , RxJava ( rx) bu tiftiksiz.


Her iki çözümünüz arasında da @SuppressLint'in en iyisi olmadığını düşünüyorum. Belki yanılıyorum ama gerçekten kodun IDE uyarılarını ve / veya ipuçlarını asla değiştirmemesi gerektiğini düşünüyorum
Arthur Attout

@ArthurAttout Kabul edildi, şu anda Disposableüye kapsamını tutuyorum dispose()ve single tamamlandığında arıyorum , ancak gereksiz yere hantal görünüyor. Bunu yapmanın daha iyi bir yolu olup olmadığını merak ediyorum.
Michael Dodd

8
RxJava akışına bir Activity / Fragment / ViewModel içinden abone olmadığında bu tüy bırakma uyarısının can sıkıcı olduğunu düşünüyorum. Aktivite yaşam döngüsüne bakılmaksızın güvenle çalışabilen bir Tamamlanabilir ürünüm var, ancak yine de onu atmam gerekiyor mu?
EM

RxLifecycle'ı düşünün
최봉재

Yanıtlar:


123

IDE, aboneliğinizin elden çıkarılmadığında ne gibi potansiyel etkilere sahip olabileceğini bilmez, bu nedenle onu potansiyel olarak güvensiz olarak değerlendirir. Örneğin, sizin yürütme sırasında terk Singleedilirse bellek sızıntısına neden olabilecek bir ağ çağrınız olabilir Activity.

Çok sayıda e-postayı yönetmenin uygun bir yolu, Disposablebir CompositeDisposable kullanmaktır ; sadece CompositeDisposableçevreleyen sınıfınızda yeni bir örnek değişkeni oluşturun , ardından tüm Tek Kullanımlık Ürünlerinizi CompositeDisposable'a ekleyin (RxKotlin ile tüm Tek Kullanımlık Ürünlerinize ekleyebilirsiniz addTo(compositeDisposable)). Son olarak, örneğinizle işiniz bittiğinde arayın compositeDisposable.dispose().

Bu, tüy bırakmayan uyarılardan kurtulacak ve Disposablesdoğru şekilde yönetilmenizi sağlayacaktır .

Bu durumda kod şöyle görünür:

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" ile derleme hatası alıyorum . Bu yöntem nereden geliyor? (Sanırım RxSwift veya RxKotlin)
aeracode

2
Evet, bu bir RxKotlin yöntemi.
acilx

1
akışkanlık durumunda ne yapmalı
Hunt

Ya bunu doOnSubscribe'da yapıyorsak
Killer

2
Bellek sızıntısına neden olmaz. Ağ çağrısı bittiğinde ve onComplete çağrıldığında, tek kullanımlık ürünün açık bir referansını tutmadığınız ve elden çıkarmadığınız sürece, çöp toplama geri kalanıyla ilgilenecektir.
Gabriel Vasconcelos

26

Etkinlik yok edileceği an, Tek Kullanımlık Ürünler listesi temizlenir ve iyiyiz.

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

10

DisposableSingleObserver ile abone olabilirsiniz :

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();
            }});

SingleNesneyi doğrudan atmanız gerektiğinde (örneğin yaymadan önce) referansı onSubscribe(Disposable d)almak ve kullanmak için yöntemi uygulayabilirsiniz Disposable.

Ayrıca SingleObserverarayüzü kendi başınıza gerçekleştirebilir veya diğer çocuk sınıflarını kullanabilirsiniz.


5

Önerildiği gibi, CompositeDisposableabone olma işleminin sonucunu buraya eklemek için bazı globalleri kullanabilirsiniz .

RxJava2Extensions kütüphanesi otomatik gelen tek kullanımlık oluşturulan kaldır yararlı yöntemler içerir CompositeDisposablezaman tamamlar. Bkz subscribeAutoDispose bölüm.

Senin durumunda böyle görünebilir

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

2

Uber AutoDispose ve rxjava'yı kullanabilirsiniz.as

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

ScopeProvider'a göre abonelikten çıktığınızda anladığınızdan emin olun.


Bu, bir yaşam döngüsü sağlayıcısının mevcut olduğunu varsayar. Ayrıca, "as" yöntemi kararsız olarak işaretlenir, bu nedenle onu kullanmak Lint uyarısına neden olur.
Dabbler

1
Teşekkürler @Dabbler, kabul etti. .As yöntem RxJava 2.1.7 kadar deneysel ve 2.2 üzerine 's istikrarlı.
blaffie

1

Tekrar tekrar kendimi aboneliklerin nasıl doğru bir şekilde imha edileceği sorusuna ve özellikle bu gönderiye dönerken buluyorum. Birkaç blog ve konuşma, arama yapmamanındispose zorunlu olarak bir bellek sızıntısına yol açtığını çok genel bir ifade. Anladığım kadarıyla sonucun saklanmaması ile ilgili tüysüz uyarı subscribebazı durumlarda sorun teşkil etmez , çünkü:

  • Tüm gözlemlenebilirler bir Android etkinliği bağlamında çalışmaz
  • Gözlenebilir eşzamanlı olabilir
  • Gözlenebilir tamamlanması koşuluyla Dispose örtük olarak çağrılır

Tüy bırakmayan uyarıları bastırmak istemediğimden, yakın zamanda senkronize bir gözlemlenebilir olan durumlar için aşağıdaki modeli kullanmaya başladım:

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

Doğruluğun teyidi veya bir boşluk keşfi olup olmadığına bakılmaksızın, bu konudaki herhangi bir yorumla ilgilenirim.


0

Tek kullanımlık ürünleri manuel olarak kullanmaktan kaçınmanın başka bir yolu vardır (abonelik ekleme ve kaldırma).

Bir Gözlemlenebilir tanımlayabilirsiniz ve bu gözlemlenebilir, içeriği bir SubjectBehaviour'dan alacaktır (RxJava kullanmanız durumunda). Ve gözlemlenebilir olanı LiveData'nıza aktararak bu işe yaramalı . İlk soruyu temel alan bir sonraki örneğe bakın:

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

Tek kullanımlık ürünün doğru şekilde kullanıldığından eminseniz, örneğin doOnSubscribe () operatörünü kullanarak, bunu Gradle'a ekleyebilirsiniz:

android {
lintOptions {
     disable 'CheckResult'
}}

10
Bu, kontrol edilmeyen bir sonucun tüm örnekleri için bu tüy bırakma kontrolünü bastıracaktır. OP örneğinin dışında, birisinin döndürülen sonucu ele alması gereken pek çok zaman vardır. Bu, bir sineği öldürmek için balyoz kullanmaktır.
tir38

16
Lütfen bunu yapmayın! Bu uyarıları almanızın bir nedeni var. Ne yaptığınızı biliyorsanız (ve gerçekten aboneliğinizi elden çıkarmanız gerekmediğini biliyorsanız) @SuppressLint("CheckResult"), sadece yöntemle bastırabilirsiniz .
Victor Rendina
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.