Доброго времени суток, друзья. Хотел бы поделиться своим не большим
велосипедом открытием в области бесконечных потоков с помощью Observable, применении их в android проектах, а так же немного рассказать теорию (если не уснете к концу статьи).
И так как же создать бесконечность? Возьмем и реализуем корекурсию с помощью нашего ленивца Observable. Почему же мы не можем применить рекурсию, ведь она в теории может быть тоже бесконечна? Потому что в теории это конечно — хорошо, но мы то программисты живем в реальном мире, а в нем мы вычисления никогда не завершим, и такая бесконечность нам не нужна.
Позвольте привести примеры c помощью «андройдовской» Java, т.к мы будем применять все это дело, после не большой модернизации, в реальном проекте:
1) Пример с рекурсией или как
не нужно делать:
public Observable<BigInteger> getState(Context context) {
BigInteger i = ZERO;
return Observable.create(
subscriber -> {
while (true) subscriber.onNext(i);
i = i.add(ONE);
}
);
}
2) Пример с отпиской или как нужно делать:
public Observable<Boolean> getNetworkState(Context context) {
BigInteger i = ZERO;
return Observable.create(
subscriber -> {
Runnable r = () -> {
while (!subscriber.isUnsubscribed())
while (true) subscriber.onNext(i);
i = i.add(ONE);
};
new Thread(r).start();
}
);
}
А теперь подробнее — что же происходит в первом и втором случае? В первом случае, рекурсия блокирует поток, по скольку вычисления никогда не кончится, и вы сами, наверняка, догадываетесь к чему это приведет. Поэтому, создадим явную конкурентность. Во втором примере мы создаем отдельный поток и будем делать события в нем.
И самое интересное то, что так как subscribe() всего лишь навсего создает новый поток, мы можем этот поток завершить всего лишь отписавшись от события. Очень удобно и без всяких interrup'ов.
Так как мы будем работать в отдельном потоке, то мы без потери производительности можем в реальном времени отслеживать различные состояния. И потом — так же легко взаимодействовать с UI через Handler.
Как же нам теперь все это применить в реальном проекте? Очень просто. Сейчас я покажу на актуальном, на мой взгляд примере — обнаружение сети.
Для начала — создадим класс, с нашим публичным Observable, на который мы можем подписаться, и приватным методом, который проверяет состояние сети. Вот код с документацией:
public class NetworkState {
/**
* @param context контекст в котором должен работать метод (<i>в основном
это будет {@link android.app.Activity}</i>)
* @return {@link Observable<Boolean>} Мгновенно возвращает состояние сети:
* <br>
* <b>true</b> - сеть есть
* </br>
*
* <br>
* <b>false</b> - сети нету
* </br>
*/
public Observable<Boolean> getNetworkState(Context context) {
return Observable.create(
subscriber -> {
Runnable r = () -> {
while (!subscriber.isUnsubscribed())
subscriber.onNext(hasConnection(context));
};
new Thread(r).start();
}
);
}
/**
* Проверка на наличие сети
* @param context Контекст
* @return <b>true</b> - сеть есть, <b>false</b> - сети нет
*/
private static boolean hasConnection(final Context context) {
ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo wifiInfo = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
NetworkInfo mobileInfo = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
return wifiInfo != null && wifiInfo.isConnected() || mobileInfo != null && mobileInfo.isConnected();
}
}
Теперь, собственно, применение (Не забудьте где нибудь проинициализировать вьюшки):
/**
* Собственно тут все очевидно, дизейблим некую кнопку и показываем сообщение в TextView, о том, что нету сети
**/
private void rxNetworkCheck(){
new NetworkManager().getNetworkState(this).subscribe(x ->
handlerNetwork.post(() -> {
if(x){
buttonNext.setVisibility(View.VISIBLE);
textViewNoConnection.setVisibility(View.INVISIBLE);
}
else{
buttonNext.setVisibility(View.INVISIBLE);
textViewNoConnection.setVisibility(View.VISIBLE);
}
})
);
}
Подведем итоги: бесконечные потоки — вполне реальны, они применимы в реальных проектах, они очень удобны и отзывчивы. При тестировании данной концепции в своем проекте я не заметил ни каких «проседаний» в производительности или других артефактов. Конечно же этот способ актуален не только для обнаружении сети, тут можно не ограничивать себя в фантазии.
Вот, собственно, и все, что я хотел сказать, надеюсь своим постом принес кому-то пользу либо проявил интерес к данной теме.
Ну и конечно же книга которая помогла мне и продолжает помогать в изучении реактивного подхода к разработки, это —
«Реактивное программирование с применением RxJava» от
Томаш Нуркевича и
Бена Кристенсена.
комментарии (35)