Comments 58
Очень рад видеть, что RxJava используется в реальном проекте. Это очень мощная библиотека, которую, ИМХО, должны использовать все Java-программисты, сталкивающиеся в своих проектах с реактивностью.
0
Отказался от использования RxJava, сильно портит читабельность и лаконичность кода.
0
Какая версия Java?
0
Android разработка, 6 версия.
0
Ну да точно, там лямбд нету. Поэтому и не лаконично. Я конечно же говорил про Java 8.
-3
У нас в мире Android большие проблемы с многопоточностью и обработкой результатов. Конечно есть кучу библиотек для этого, но все равно пока нет ничего лаконичного и красивого, чтобы код душу радовал.
0
А почему дайлер так долго стартует, до сих пор? При старте раскручивается данный аппарат, и эта задача полностью загружает девайс, что UI потоку не хватает «места» отрендерить клавиатурку и лоадинг истории вызовов? Спасибо.
+3
Возможно ребята увлеклись многопоточностью. В свое время сравнивал что лучше — 4 тяжелых потока одновременно или последовательно. Результат удивил — по скорости многопоточность выиграла, но не в 4 раза быстрее, а процентов на 20-30. С другой стороны 4 одновременных потока очень сильно нагрели смартфон. Хотя сейчас это уже не так существенно. Сам стартую по 3 потока за раз, тем более что с android query это выглядит не менее изящно чем с RxJava:
aq.progress(this).ajax(getCallBack(this, "user.get"));
aq.progress(this).ajax(getCallBack(this, "user.getCategories"));
aq.progress(this).ajax(getCallBack(this, "user.getChannelsWithTags&type=channels"));
-4
ах, да еще и кеширование из коробки^^ обработка вьюх как в груви, работа с картинками и никаких жалких аутофмемори
Нет уж ребят, лучше Вы к нам
public static AjaxCallback getCallBack(Object o,String method) {
String url = SurfingServiceImpl.API_URL+"?method="+method;
AjaxCallback<String> cb = new AjaxCallback<String>();
cb.url(url).type(String.class).weakHandler(o, "onRefresh").fileCache(true).expire(1000 * 15);
cb.header("Authorization", "Bearer " + SurfingbirdApplication.getInstance().getSettings().getLoginToken());
return cb;
}
Нет уж ребят, лучше Вы к нам
-2
UFO just landed and posted this here
Цитата нужна? Поясню. Я искал узкое место в коде и возможности оптимизации. Выяснилось что 4 http запроса в 4 потока не будут быстрее в 4 раза 4 последовательных запросов. Но буквально раскаляли телефон (это был Нексус 3 по моему). По всей видимости это связано с тем что основные накладные расходы связаны с инициализацией http клиента, установкой соединения и так далее. Вобщем должно быть очевидно что реальные задачи сильно расходятся с синтетическими тестами. Кстати узкое место я тогда нашел, и им оказался дефолтный JSON парсер. Переход на SAX парсер дал прирост раз в 100 и облегчил работу GC.
Хотя в данном конретном случае — не думаю что дело в потоках вообще. Скорее всего инициализация/работа RxJava занимает много времени. За все надо платить. Нравятся Скала, RxJava — используйте. Но за Ваш комфорт программиста заплатят пользователи своим временем. И кстати в андроидквери вы заплатите увеличением программы килобайт на 200 и не потеряете в производительности. А получите то же самое. Вобщем я останусь ретроградом и продолжу кодить на яве.
Хотя в данном конретном случае — не думаю что дело в потоках вообще. Скорее всего инициализация/работа RxJava занимает много времени. За все надо платить. Нравятся Скала, RxJava — используйте. Но за Ваш комфорт программиста заплатят пользователи своим временем. И кстати в андроидквери вы заплатите увеличением программы килобайт на 200 и не потеряете в производительности. А получите то же самое. Вобщем я останусь ретроградом и продолжу кодить на яве.
-2
Выяснилось что 4 http запроса в 4 потока не будут быстрее в 4 раза 4 последовательных запросов.
в Android SDK до сих пор не завезли честные асинхронные сетевые запросы, обязательно использовать треды?
-2
UFO just landed and posted this here
Мы сейчас в википедии? о_О Я рассказал о своем исследовании и своих выводах, вот и все. Если Вам оно в чем то непонятно или Вы с ним не согласны — проведите свое.
-4
Там не виснет UI, просто зеленый экран и ничего не происходит. Почему так? Потому что в дайлере все еще есть архитектурные части, которые требуют инициализации при старте приложения. Правильным решением является устранение этой необходимости, а не
ProgressBar
перед историей вызовов. Они никак не относятся к RxJava. Какая вообще может быть инициализация у RxJava? Ее нет. Разве что создание тред пулов и все вот это, но оно никак не трогает старт приложения.+3
Давно уже не использую AsyncTask, т.к. в аднроиде появились Loaders.
Возникает вопрос: как эта библиотека работает в случаях смены конфигурации экрана, например?
Возникает вопрос: как эта библиотека работает в случаях смены конфигурации экрана, например?
0
github.com/evant/rxloader попробуйте это
+1
Давно уже не использую Loaders, т.к. в android «появились» сервисы
+1
RxJava прекрасно работает в случаях смены конфигурации экрана. Ее это просто не трогает.
Observable
не привязан к Context
' у активити, если вы все правильно делаете. И дальше вам решать, что и как делать.0
Можно поподробнее отсюда? Если RxJava так же, как и AsyncTask работают внутри фрагментов, то при смене ориентации дисплее они будут запущены по новой.
0
или у вас все фрагменты setRetainInstance(true)?
0
Нет, конкретно у нас просто только портрет ориентация поддерживается, вот и все. А на деле все работает хорошо, потому что внутри себя
Observable
все-таки никак не связан с контекстом активити, только с контекстом самого Application
. А при перевороте он сохраняется. А подписываться и отписываться (для того, чтобы обрабатывать и менять UI) можно хоть-сколько раз.0
Приятно видеть что люди стали открывать для себя событийные языки. Но пока чтоRxJava не идет ни в какое сравнение ни с SystemC, ни с VHDL, ни c Verilog.
0
Мы у себя тоже используем RxJava, очень довольны.
> (были бы лямбды — был бы еще и красивым)
Это решается с помощью retrolambda:
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:0.11.+'
classpath 'me.tatarka:gradle-retrolambda:1.3.+'
}
}
apply plugin: 'retrolambda'
retrolambda {
jdk System.getenv(«JAVA8_HOME»)
}
dependencies {
retrolambdaConfig 'net.orfjackal.retrolambda:retrolambda:1.+'
compile 'com.netflix.rxjava:rxjava-android:0.19.+'
compile 'com.netflix.rxjava:rxjava-async-util:0.19.+'
}
P.S. извиняюсь,
> (были бы лямбды — был бы еще и красивым)
Это решается с помощью retrolambda:
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:0.11.+'
classpath 'me.tatarka:gradle-retrolambda:1.3.+'
}
}
apply plugin: 'retrolambda'
retrolambda {
jdk System.getenv(«JAVA8_HOME»)
}
dependencies {
retrolambdaConfig 'net.orfjackal.retrolambda:retrolambda:1.+'
compile 'com.netflix.rxjava:rxjava-android:0.19.+'
compile 'com.netflix.rxjava:rxjava-async-util:0.19.+'
}
P.S. извиняюсь,
почему то не работает :(
0
все работает. lambdas, rxjava, retrolambda, AS 0.8.1
вот тут есть работающий пример, из которого я брал конфиг
github.com/fs/android-base
вот тут есть работающий пример, из которого я брал конфиг
github.com/fs/android-base
0
Не возникало ли проблем с дебагом такого кода? Или при анализе стектрейсов, если что-то внутри Observable упало?
PS Спасибо за интересную статью.
PS Спасибо за интересную статью.
+1
Нет, никаких проблем. Android Studio спокойно заходит во все тела всех
Со стектрейсами все ок, читабельно, ее умные ребята делали.
Observable
и все хорошо. Единственное, что затрудняет дебаг, так это пошаговая отладка, потому что на пути от onNext()
до, например, flatMap
, если произошел retry()
происходит много внутренних преобразований.Со стектрейсами все ок, читабельно, ее умные ребята делали.
0
«Подобный код встречается во многих проектах, он понятен, а миллионы леммингов не могут ошибаться. Но давайте копнём чуть глубже:
Что делать, если где-то во время выполнения выпал Exception?
doInBackground(Void...) выполняется в отдельном потоке, как нам сказать пользователю об ошибке в UI? Заводить поля для Exception?
А что возвращать, если не прошел запрос? null?
А если json не валидный?
Что стоит делать, если не удалось кэшировать объект?
»
Возвращать из doInBackground не JSONObject, а экземпляр своего класса, у которого, скажем, будет два поля: status, msg, object. Если в doInBackground ошибка/исключение, то возвращаем из него свой объект с соответствующим статусом и сообщением. Потом в onPostExecute проверяем сие поле и уведомляем UI (так как doInBackground имеет доступ к UI). Так что проблема, по-моему, выдуманная )
Что делать, если где-то во время выполнения выпал Exception?
doInBackground(Void...) выполняется в отдельном потоке, как нам сказать пользователю об ошибке в UI? Заводить поля для Exception?
А что возвращать, если не прошел запрос? null?
А если json не валидный?
Что стоит делать, если не удалось кэшировать объект?
»
Возвращать из doInBackground не JSONObject, а экземпляр своего класса, у которого, скажем, будет два поля: status, msg, object. Если в doInBackground ошибка/исключение, то возвращаем из него свой объект с соответствующим статусом и сообщением. Потом в onPostExecute проверяем сие поле и уведомляем UI (так как doInBackground имеет доступ к UI). Так что проблема, по-моему, выдуманная )
+2
fix: конечно же, onPostExecute имеет доступ к UI, а не doInBackground
0
UFO just landed and posted this here
Если во время работы doInBackground возникает исключительная ситуация, выполнение асинк-таска можно закончить методом cancel(). В таком случае вместо onPostExecute вызовется onCancelled() в аргументах которого вы можете передать и причину и объект, если зохочется.
0
А если я не хочу
cancel()
, а хочу еще раз попробовать сделать запрос? Понятно, что ASyncTask вполне самодостаточная вещь в каокм-то смысле. Но ее функционал все же ограничен, стоит признать.0
Непонятно только одно: при чем тут андроид?
0
А при том, что у нас в 2GisDialer используется RxJava. А 2GisDialer — это приложение, написанное под Android OS. Кроме того, в статье приведено сравнение подходов к многопоточности в Android с использованием ASyncTask и Observable. Также замечу, что класс ASyncTask является частью Android SDK и его нет в Java.
0
Против самого примера ничего не имею, я о другом. Если не знать что такое RxJava и читать по диагонали, то можно упустить важный факт, что RxJava — это не только «под Android». Т.е. значительно лучше было бы акцентировать внимание на том, что это для «Java в общем, и для Android в частности». Я, например, уверен, что многие люди уже из-за одного названия статью просто не открыли.
+1
Проблемы, с которыми мы столкнулись
Вам не кажеться что одна проблема вытекает из другой и количество потоков тут не причем (так как приходилось и с большим количеством работать, которые обрабатывали видео/аудио).
Вы кешируете каждый пчих в lru cache, который храниться в памяти (±32Мб — размер кеша). Вот и получаеться что чем больше потоков тем больше записи в lru cache, тем больше вызова GC после вытеснения, а вот GC умеет останавливает UI Thread и вам кажеться что это потоки тупят систему, а на самом деле вызовы GC в лучшем случае линейно зависят от количчества потоков.
Учитывая что вставка идет JSON, то это подразумевает Network операции, это тоже память, а если где то паралельно грузяться картинки (упаси в оригинальном размере), то не удевительно что у вас просто тупит приложение из за частого вызова GC. А ограничение в 4-е потока это просто приемлемый хак, но не решение проблемы.
+1
final Subscription subscription = Observable.create(new Observable.OnSubscribe<String>() {
Разве не так?
final Observable observable =
Observable.create(new Observable.OnSubscribe<String>() {
Как раз решил разобраться с Java RX. Пример не пошел
0
Там наверное в конце пропущено }).subscribe();
+1
Именно. Убрал за ненадобностью в примере, а тип ссылки не поменял.
0
Попробовал на фиде конверторе
github.com/app-z/CurrencyConverter2
Тогда еще вопрос задам, специалусту в RX Java
final Subscription subscription =…
Не надо делать unSubscribe в onDestroy? Т.е. я имею ввиду выносить наружу subscription из метода или из onCreate и делать член класса
Я к тому что сабскрайбер сам разберется когда прервать работу если активити уничтожается?
github.com/app-z/CurrencyConverter2
Тогда еще вопрос задам, специалусту в RX Java
final Subscription subscription =…
Не надо делать unSubscribe в onDestroy? Т.е. я имею ввиду выносить наружу subscription из метода или из onCreate и делать член класса
Я к тому что сабскрайбер сам разберется когда прервать работу если активити уничтожается?
0
Теоретически CachedThreadPool тоже может положить приложение, если, к примеру, одновременно в пул на выполнение отправляются штук 20 немаленьких задач, таким образом создается штук 20 потоков.
В AsyncTask, например, создается ThreadPoolExecutor c параметрами CORE_POOL_SIZE = CPU_COUNT + 1 и MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1, где CPU_COUNT — количество процессоров на устройстве. Таким образом, если на устройстве 2 процессора, то количество потоков не будет превышать 5. По идее данный вариант самый безопасный. Но и с вашим вероятность падения очень маленькая.
А так, спасибо за статью, весьма полезная)
В AsyncTask, например, создается ThreadPoolExecutor c параметрами CORE_POOL_SIZE = CPU_COUNT + 1 и MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1, где CPU_COUNT — количество процессоров на устройстве. Таким образом, если на устройстве 2 процессора, то количество потоков не будет превышать 5. По идее данный вариант самый безопасный. Но и с вашим вероятность падения очень маленькая.
А так, спасибо за статью, весьма полезная)
+1
Полностью согласен с вами. Добавлю так же, что лучше создавать несколько тредпулов с меньшим количеством тредов.
Например, тредпул с CPU_COUNT/2 для работы с сетью, такой же для выполнения рутинных задач и FixedThreadPoolExecutor на 2-3 треда для выполнения очень приоритетных задач (коих должно быть не много по задумке).
Так проще регулировать работы обсерваблов, если их становится много, а так же позволяет приоритезировать задачи. Обычно это работает неплохо.
Например, тредпул с CPU_COUNT/2 для работы с сетью, такой же для выполнения рутинных задач и FixedThreadPoolExecutor на 2-3 треда для выполнения очень приоритетных задач (коих должно быть не много по задумке).
Так проще регулировать работы обсерваблов, если их становится много, а так же позволяет приоритезировать задачи. Обычно это работает неплохо.
+1
Было бы классно, если бы Вы добавили в статью решение еще одного примера.
Есть у нас метод запроса в сеть с параметрами offset, limit. Назовем метод request(int offset, int limit). Нам нужно получить весь массив данных. То есть скорее всего придется вызвать несколько раз request с разными параметрами offset и limit, и полученные массивы соединить в один.
Один облегчающий фактор в том, что метод request возвращает Observable (то есть работаем через RetroFit).
Собственно как должна выглядеть вся портянка итогового Observable, чтобы при подписке к нему, мы сразу получали весь массив данных?
Честно говоря, сколько гуглил, так и не смог найти понятного примера. Может вы с этим уже сталкивались?)
Есть у нас метод запроса в сеть с параметрами offset, limit. Назовем метод request(int offset, int limit). Нам нужно получить весь массив данных. То есть скорее всего придется вызвать несколько раз request с разными параметрами offset и limit, и полученные массивы соединить в один.
Один облегчающий фактор в том, что метод request возвращает Observable (то есть работаем через RetroFit).
Собственно как должна выглядеть вся портянка итогового Observable, чтобы при подписке к нему, мы сразу получали весь массив данных?
Честно говоря, сколько гуглил, так и не смог найти понятного примера. Может вы с этим уже сталкивались?)
0
Sign up to leave a comment.
Реактивное программирование под Android