Intereting Posts
Функция Котлина с нулевым / ненулевым вводом, отображаемым на нулевой / ненулевой вывод Kotlin: как параметр по умолчанию в «fun main (parameters: Array <String>)» печатает «гость» без присвоения каких-либо значений Как десериализовать JSON в List <SomeType> с помощью Kotlin + Jackson Могу ли я использовать два xml-макета для использования одного и того же зрителя с использованием синтетических расширений Kotlin? Kotlin, таблица / массив на основе записей с динамическими полями NullPointerException в Android Studio 3 Beta 1 Почему «возврат» не разрешен в блоке init Kotlin? Ленивая инициализация свойства класса Kotlin не будет компилироваться Как сделать сумму элементов для нескольких списков в kotlin kotlin unreachable code при использовании finally и enum Kotlin: Сделать внутреннюю функцию видимой для модульных тестов IntelliJ IDEA с использованием JavaScript-версии зависимости, указанной в файле сборки Gradle? Kotlin четверка, пятикратная и т. Д. Для деструктурирования Тип универсального парного типа для дополнительных целей Обоснованные дженерики в Scala 2.10

Функция расширения не создает новый объект Observable

У меня неожиданное поведение с котлин и 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 com.squareup.picasso.Picasso@c894e26 09-28 11:17:00.068 31694-32277/? D/picasso load bitmap: me com.squareup.picasso.Picasso@c894e26 09-28 11:17:00.069 31694-31959/? D/picasso load bitmap: me com.squareup.picasso.Picasso@c894e26 09-28 11:17:00.108 31694-32278/? D/picasso load bitmap: me com.squareup.picasso.Picasso@c894e26 09-28 11:17:00.112 31694-32251/? D/picasso load bitmap: me com.squareup.picasso.Picasso@c894e26 09-28 11:17:00.125 31694-32260/? D/picasso load bitmap: me com.squareup.picasso.Picasso@c894e26 09-28 11:17:00.162 31694-31794/? D/picasso load bitmap: me com.squareup.picasso.Picasso@c894e26 09-28 11:17:00.192 31694-32280/? D/picasso load bitmap: me com.squareup.picasso.Picasso@c894e26 09-28 11:17:00.195 31694-32279/? D/picasso load bitmap: me com.squareup.picasso.Picasso@c894e26 09-28 11:17:00.219 31694-32281/? D/picasso load bitmap: me com.squareup.picasso.Picasso@c894e26 09-28 11:17:04.828 31694-32262/? D/picasso load bitmap: me com.squareup.picasso.Picasso@c894e26 09-28 11:17:14.885 31694-31793/? D/picasso load bitmap: me com.squareup.picasso.Picasso@c894e26 09-28 11:17:29.928 31694-32269/? D/picasso load bitmap: me com.squareup.picasso.Picasso@c894e26 

Наблюдаемый одинаковый для всех вызовов loadBitmap . Мне нужно, чтобы у них было собственное наблюдение, потому что, если я не буду, когда retryWhen не удастся, он не retryWhen к следующему сбою. Надеюсь, это имеет смысл.

Помещение наблюдаемого внутри defer или flatmap ничего не изменит.

ИЗМЕНИТЬ мой код

 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, просто для вас, чтобы увидеть немного шире. Таким образом, это функция внутри VIEW, рендеринг будет запущен после того, как MODEL завершит получение данных с сервера.

Вы должны быть осторожны. Ключевое слово this в

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

не ориентируется на Observable но тип приемника. В вашем случае Picasso . Вы видите, что в вашем журнале me com.squareup.picasso.Picasso@c894e26

Хорошей новостью является то, что вы получаете новый экземпляр Observable для каждого вызова loadBitmap . Вы можете проверить это:

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

Итак, вы видите, вы вызываете loadBitmap всегда на одном экземпляре picasso , поэтому вы получаете тот же результат для этого класса. Но каждый индивидуальный вызов loadBitmap создает новый Observable

Так что ваш код в порядке.