2017-09-28 102 views
0

我遇到意外的kotlin和rxjava行爲。我用畢加索創造加載圖像的擴展功能擴展函數不會創建新的可觀察對象

fun Picasso.loadBitmap(url: String) : Observable<Bitmap> 
     = Observable.create<Bitmap> { 
    emitter -> 
    Log.d("picasso load bitmap", "me ${this}") 
    try { 
     val bitmap = load(url).centerCrop() 
       .resize(100, 100) 
       .transform(CircleTransformer()) 
       .get() 
     emitter.onNext(bitmap) 
     emitter.onComplete() 
    } catch (e: IOException) { 
     emitter.onError(e) 
    } 
} 

林調用一個閉區間(幾乎在同一時間)這個多次這樣的,

picasso.loadBitmap(place.image_url) 
    .subscribeOn(Schedulers.io()) 
    .retryWhen { error -> 
     error.zipWith(Observable.range(1, 5), 
       BiFunction<Throwable, Int, RetryWrapper> { 
        t1, t2 -> RetryWrapper(t2.toLong(), t1) }) 
       .flatMap { 
        if(it.delay < 4){ 
         Log.d(TAG, "retry no. ${it.delay} for ${place.image_url}") 
         Observable.timer(it.delay * 5, TimeUnit.SECONDS) 
        } else { 
         Log.d(TAG, "DMD ${place.image_url}") 
         Observable.error { it.error } 
        } 
       } 

    } 
    .subscribe (
     { bitmap -> 
      markers.find { it.place.id == place.id }?.let { 
       it.marker.icon = IconFactory.getInstance(context).fromBitmap(bitmap) 
      } 
     }, 
     { 
      Log.e(TAG, "error decoding ${place.image_url}", it) 
     }) 

我希望每一次loadBitmap會被調用,它會創建一個新的可觀察值。但我在日誌中得到這個

09-28 11:17:00.022 31694-32276/? D/picasso load bitmap: me [email protected] 
09-28 11:17:00.068 31694-32277/? D/picasso load bitmap: me [email protected] 
09-28 11:17:00.069 31694-31959/? D/picasso load bitmap: me [email protected] 
09-28 11:17:00.108 31694-32278/? D/picasso load bitmap: me [email protected] 
09-28 11:17:00.112 31694-32251/? D/picasso load bitmap: me [email protected] 
09-28 11:17:00.125 31694-32260/? D/picasso load bitmap: me [email protected] 
09-28 11:17:00.162 31694-31794/? D/picasso load bitmap: me [email protected] 
09-28 11:17:00.192 31694-32280/? D/picasso load bitmap: me [email protected] 
09-28 11:17:00.195 31694-32279/? D/picasso load bitmap: me [email protected] 
09-28 11:17:00.219 31694-32281/? D/picasso load bitmap: me [email protected] 
09-28 11:17:04.828 31694-32262/? D/picasso load bitmap: me [email protected] 
09-28 11:17:14.885 31694-31793/? D/picasso load bitmap: me [email protected] 
09-28 11:17:29.928 31694-32269/? D/picasso load bitmap: me [email protected] 

可觀察的是所有loadBitmap調用相同。 我需要他們有自己的觀察,因爲如果我不會,當retryWhen失敗時,它不會繼續下一個失敗。我希望這是有道理的。

deferflatmap中的可觀察內容不會改變任何內容。

編輯我的代碼

override fun render(state: MainState) { 
     map?.let { map -> 
      val newMarkers: MutableList<PlaceMarker> = mutableListOf() 
      for(place in state.places) { 
       var placeMarker = placeMarkers.find { it.place.id == place.id } 
       if(placeMarker != null && map.markers.contains(placeMarker.marker)) { 
        newMarkers.add(placeMarker) 
        placeMarkers.remove(placeMarker) 
       } else { 
        if(placeMarker != null) placeMarkers.remove(placeMarker) 
        val option = MarkerOptions() 
        option.position = LatLng(place.latitude, place.longitude) 
        option.snippet = place.name 
        placeMarker = PlaceMarker(place, map.addMarker(option)) 
        newMarkers.add(placeMarker) 

        picasso.loadBitmap(place.image_url) 
          .subscribeOn(Schedulers.io()) 
          .retryWhen { error -> 
           error.zipWith(Observable.range(1, 5), 
             BiFunction<Throwable, Int, RetryWrapper> { 
              t1, t2 -> RetryWrapper(t2.toLong(), t1) }) 
             .flatMap { 
              if(it.delay < 4){ 
               Log.d(TAG, "retry no. ${it.delay} for ${place.image_url}") 
               Observable.timer(it.delay * 5, TimeUnit.SECONDS) 
              } else { 
               Log.d(TAG, "DMD ${place.image_url}") 
               Observable.error { it.error } 
              } 
             } 
          } 
          .subscribe (
            { bitmap -> 
             placeMarkers.find { it.place.id == place.id }?.let { 
              it.marker.icon = IconFactory.getInstance(context).fromBitmap(bitmap) 
              bitmap.recycle() 
             } 
            }, 
            { 
             Log.e(TAG, "error decoding ${place.image_url}", it) 
            }) 
       } 

      } 
      placeMarkers.forEach { it.marker.remove() } 
      placeMarkers.clear() 
      placeMarkers.addAll(newMarkers) 
     } 
    } 

進出口使用的MVP,只是給你看廣一點。因此,在MODEL完成從服務器獲取數據之後,VIEW,render中的函數將被觸發。

回答

3

你必須在這裏小心。在

Log.d("picasso load bitmap", "me ${this}") 

關鍵字this不瞄準Observable但接收器類型。在你的情況Picasso。你看到在你的日誌me [email protected]

好消息是,你得到Observable的每個呼叫loadBitmap的新實例。

val observable = picasso.loadBitmap(place.image_url) 
Log.d("observable for picasso", "$observable") 
observable.subscribeOn(Schedulers.io())... 

所以你看,你叫loadBitmap總是在picasso相同的實例,這就是爲什麼你的這個類相同的輸出:您可以通過檢查。但是每個撥打loadBitmap的電話都會創建一個新的Observable

因此,您的代碼很好。

+0

謝謝,但爲什麼我只能得到1個週期的重試,沒有更多?我只能得到1個加載錯誤,但我有更多的網址加載。 – Hohenhiem

+0

你可以添加一些關於這個問題的更多細節。 – guenhter

+0

對不起, 我有從服務器獲取的地點列表。這個地方有img_urls,我需要在每個地方做一個標記,同時產生一個可觀察的圖像加載。 發生什麼事是,當我得到重試周期時,它不會繼續加載其餘的imgs。我希望這是有道理的。我張貼代碼。 – Hohenhiem

相關問題