- Работа с сетью в Android с использованием корутин и Retrofit
- Настройка сети на Андроиде
- Настройка сети на Андроид
- Как настроить тип сети на Андроид
- Почему пропадает сеть на Андроиде
- Как усилить сигнал на Андроид
- Что делать, если Андроид не видит сеть?
- Как сделать сброс настроек сети на Андроид?
- Взаимодействие Android-устройств в локальной сети
- О чем это и для кого это?
- Какие возможные способы решения существуют?
Работа с сетью в Android с использованием корутин и Retrofit
Чем больше я читал и смотрел доклады про корутины в Kotlin, тем больше я восхищался этим средством языка. Недавно в Kotlin 1.3 вышел их стабильный релиз, а значит, настало время начать погружение и опробовать корутины в действии на примере моего существующего RxJava-кода. В этом посте мы сфокусируемся на том, как взять существующие запросы к сети и преобразовать их, заменив RxJava на корутины.
Откровенно говоря, перед тем как я попробовал корутины, я думал, что они сильно отличаются от того, что было раньше. Однако, основной принцип корутин включает те же понятия, к которым мы привыкли в реактивных потоках RxJava. Для примера давайте возьмем простую конфигурацию RxJava для создания запроса к сети из одного моего приложения:
- Определяем сетевой интерфейс для Ретрофита, используя Rx-адаптер (retrofit2:adapter-rxjava2). Функции будут возвращать объекты из Rx-фреймворка, такие как Single или Observable. (Здесь и далее используются функции, а не методы, так как предполагается, что старый код был также написан на Kotlin. Ну или сконвертирован из Java через Android Studio).
- Вызываем определенную функцию из другого класса (например репозитория, или активити).
- Определяем для потоков, на каком Scheduler-е они будут выполняться и возвращать результат (методы .subscribeOn() и .observeOn()).
- Сохраняем ссылку на объект для отписки (например в CompositeObservable).
- Подписываемся на поток эвентов.
- Отписываемся от потока в зависимости от событий жизненного цикла Activity.
Это основной алгоритм работы с Rx (не учитывая функции маппинга и детали других манипуляций с данными). Что касается корутин – принцип сильно не меняется. Та же концепция, меняется только терминология.
- Определяем сетевой интерфейс для Ретрофита, используя адаптер для корутин. Функции будут возвращать Deferred объекты из API корутин.
- Вызываем эти функции из другого класса (например репозитория, или активити). Единственное отличие: каждая функция должна быть помечен как отложенная (suspend).
- Определяем dispatcher, который будет использован для корутина.
- Сохраняем ссылку на Job-объект для отписки.
- Запускаем корутин любым доступным способом.
- Отменяем корутины в зависимости от событий жизненного цикла Activity.
Как можно заметить из приведенных выше последовательностей, процесс выполнения Rx и корутин очень похож. Если не учитывать детали реализации, это означает, что мы можем сохранить подход, который у нас есть – мы только заменяем некоторые вещи, чтобы сделать нашу реализацию coroutine-friendly.
Первый шаг, который мы должны сделать – позволить Ретрофиту возвращать Deferred-объекты. Объекты типа Deferred представляют собой неблокирующие future, которые могут быть отменены, если нужно. Эти объекты по сути представляют собой корутинную Job, которая содержит значение для соответствующей работы. Использование Deferred типа позволяет нам смешать ту же идею, что и Job, с добавлением возможности получить дополнительные состояния, такие как success или failure – что делает его идеальным для запросов к сети.
Если вы используете Ретрофит с RxJava, вероятно, вы используете RxJava Call Adapter Factory. К счастью, Джейк Вортон написал её эквивалент для корутин.
Мы можем использовать этот call adapter в билдере Ретрофита, и затем имплементировать наш Ретрофит-интерфейс так же, как было с RxJava:
Теперь посмотрим на интерфейс MyService, который использован выше. Мы должны заменить в Ретрофит-интерфейсе возвращаемые Observable-типы на Deferred. Если раньше было так:
То теперь заменяем на:
Каждый раз, когда мы вызовем getData() – нам вернется объект Deferred – аналог Job для запросов к сети. Раньше мы как-то так вызывали эту функцию с RxJava:
В этом RxJava потоке мы вызываем нашу служебную функцию, затем применяем map-операцию из RxJava API с последующим маппингом данных, вернувшихся из запроса, в что-то, используемое в UI слое. Это немного поменяется, когда мы используем реализацию с корутинами. Для начала, наша функция должна быть suspend (отложенной), для того, чтобы сделать ленивую операцию внутри тела функции. И для этого вызывающая функция должна быть также отложенной. Отложенная функция – неблокирующая, и ею можно управлять после того, как она будет первоначально вызвана. Можно ее стартануть, поставить на паузу, возобновить или отменить.
Теперь мы должны вызвать нашу служебную функцию. На первый взгляд, мы выполняем то же самое, но нужно помнить, что теперь мы получаем Deferred вместо Observable.
Из-за этого изменения мы не можем больше использовать цепочку map-операция из RxJava API. И даже в этой точке нам не доступны данные – мы только имеем Deferred-инстанс. Теперь мы должны использовать функцию await() для того, чтобы дождаться результата выполнения запроса и затем продолжить выполнение кода внутри функции:
В этой точке мы получаем завершенный запрос и данные из него, доступные для использования. Поэтому мы можем теперь совершать операции маппинга:
Мы взяли наш Ретрофит-интерфейс вместе с вызывающим классом и использовали корутины. Теперь же мы хотим вызвать этот код из наших Activity или фрагментов и использовать данные, которые мы достали из сети.
В нашей Activity начнем с создания ссылки на Job, в которую мы сможем присвоить нашу корутинную операцию и затем использовать для управления, например отмены запроса, во время вызова onDestroy().
Теперь мы можем присвоить что-то в переменную myJob. Давайте посмотрим на наш запрос с корутинами:
В этом посте я не хотел бы углубляться в Dispatchers или исполнение операций внутри корутинов, так как это тема для других постов. Вкратце, что здесь происходит:
- Создаем инстанс CoroutineScope, используя IO Dispatcher в качестве параметра. Этот диспатчер используется для совершения блокирующих операций ввода-вывода, таких как сетевые запросы.
- Запускаем наш корутин функцией launch – эта функция запускает новый корутин и возвращает ссылку в переменную типа Job.
- Затем мы используем ссылку на наш репозиторий для получения данных, выполняя сетевой запрос.
- В конце мы используем Main диспатчер для совершения работы на UI-потоке. Тут мы сможем показать полученные данные пользователям.
В следующем посте автор обещает копнуть поглубже в детали, но текущего материала должно быть достаточно для начала изучения корутинов.
В этом посте мы заменили RxJava-реализацию ответов Ретрофита на Deferred объекты из API корутин. Мы вызываем эти функции для получения данных из сети, и затем отображем их в нашем активити. Надеюсь, вы увидели, как мало изменений нужно сделать, чтобы начать работать с корутинами, и оценили простоту API, особенно в процессе чтения и написания кода.
В комментариях к оригинальному посту я нашел традиционную просьбу: покажите код целиком. Поэтому я сделал простое приложение, которое при старте получает расписание электричек с API Яндекс.Расписаний и отображает в RecyclerView. Ссылка: https://github.com/AndreySBer/RetrofitCoroutinesExample
Еще хотелось бы добавить, что корутины кажутся неполноценной заменой RxJava, так как не предлагают равноценного набора операций для синхронизации потоков. В этой связи стоит посмотреть на реализацию ReactiveX для Kotlin: RxKotlin.
Источник
Настройка сети на Андроиде
Настройка сети на Андроиде. На сегодняшний день настройка сети на Андроид в большинстве случаев происходит автоматически, но иногда для подключения или выбора параметров сети все-таки может потребоваться участие пользователя.
Настройка сети на Андроид
Для получения доступа к сети зачастую достаточно вставить в устройство сим-карту. Вам нужно убедиться в том, что сим-карта активирована и имеет подключенные услуги сотовой связи. По умолчанию в настройках включен автоматический выбор оператора, смартфон сам найдет сеть и подключится к ней. Если нет — включите этот параметр или выберите вашего оператора из списка доступных самостоятельно.
Как настроить тип сети на Андроид
Современные смартфоны имеют возможность работать в нескольких типах (поколениях) сети: 2G, 3G и 4G (LTE). По умолчанию радиомодуль будет пытаться подключиться к сети высшего поколения, если не получится — будет пытаться подключиться к сети поколением ниже. Такой постоянный поиск лучшей сети негативно отражается на заряде аккумулятора. Если вы знаете, что в вашем регионе преимущественно распространена сеть 3G, можете выбрать соответствующий параметр в настройках, тем самым избавив устройство от лишней нагрузки при поиске 4G. Если же вы не используете интернет для просмотра видео или скачивания больших файлов, можно вообще выбрать сеть 2G. Скорость интернета в данной сети оставляет желать лучшего, но такая настройка сети на Андроид поможет аккумулятору дольше держать заряд.
Настройка интернета на Андроид тоже происходит автоматически, как и настройка сети на Андроид. Однако могут быть исключения:
- Если вы приобрели смартфон от какого-то малоизвестного производителя, для устройств которого нет автоматических настроек, то настройки придется вводить вручную.
- Если смартфон выпущен для другой страны. В таком случае подключение к сети может и вовсе быть невозможным, так как в разных странах для сотовой связи могут использоваться разные частоты.
Для того, чтобы ввести настройки интернета вручную, вам нужно уточнить в технической поддержке вашего оператора необходимые параметры для точки доступа (APN) и создать новую точку доступа.
Почему пропадает сеть на Андроиде
Время от времени у смартфонов на Андроид, как и у всех сотовых телефонов, могут наблюдаться проблемы с качеством подключения к сети. Есть множество факторов, влияющих на уровень сигнала, дело может быть вовсе не в самом устройстве или операторе. Вот некоторые причины, по которым падает качество связи и скорость интернета:
- Большое расстояние до ближайшей вышки АТС (автоматическая телефонная станция) — особенно заметно за пределами крупных населенных пунктов.
- Загруженность вышки сотовой связи — если много абонентов одновременно подключены к одной вышке и используют интернет, то его скорость для каждого абонента падает.
- Погодные условия — во время дождя радиорелейные каналы связи резко теряют свою пропускную способность.
- Плотность застройки и другие преграды на пути сигнала. Бывает так, что из-за преград устройство не может поймать сигнал ближайшей АТС и подключается к более удаленной.
- Качество вашего смартфона — приобретая бюджетное устройство, вы должны понимать, что в нем установлены не самые лучшие компоненты.
- Некоторые чехлы также негативно влияют на качество получаемого сигнала.
Как усилить сигнал на Андроид
Для усиления сигнала в населенных пунктах и за их пределами используются так называемые репитеры GSM/3G. Устройство представляет собой усиленную антенну, которая способна уловить слабый сигнал и усилить его для использования абонентами. Также есть приложения, призванные повысить качество связи. Сам сигнал они не улучшают, но они сканируют ближайшие вышки сотовой связи и подключаются к той, у которой сигнал лучше. Если вы испытываете проблемы со связью, можете попробовать приложение Network Signal Information Pro .
Что делать, если Андроид не видит сеть?
Если у вас установлен тип сети только 4G или 3G, попробуйте поменять его на другой. Бывает так, что какой-то определенный тип сети либо перегружен, либо имеет слабый сигнал, тогда как у других типов сети сигнал стабильный.
Как сделать сброс настроек сети на Андроид?
Для того, чтобы сделать сброс настроек сети к стандартным настройкам сим-карты, нужно:
- Зайти в настройки беспроводных сетей
- Выбрать пункт меню «Мобильные сети»
- Нажать «Сброс на значения по умолчанию»
Источник
Взаимодействие Android-устройств в локальной сети
Предположим, мы пишем игру для Android, которая подразумевает некое сетевое взаимодействие между устройствами. Причем наши устройства находятся в одной сети и мы хотим, чтобы взаимодействие между ними осуществлялось быстро, а значит вариант с обменом данными через интернет нам не подходит. Ах да, еще одна маленькая ложка дегтя — мы хотим охватить максимально возможную аудиторию, для чего нам необходимо поддерживать Android 2.3.
Что же нам делать? Давайте поговорим об этом, а заодно рассмотрим относительно новые возможности Android SDK для соединения двух и более устройств.
О чем это и для кого это?
Как-то раз, уйдя с предыдущего места работы и погрузившись в заслуженный отдых, я принялся писать сетевую игру, в которую могут играть люди, находящиеся в одной локальной сети. И сразу же столкнулся с тем, что для нормального функционирования подобной игры нам мало соорудить сетевое взаимодействие — нам нужно сделать нормальное и быстрое обнаружение устройств в сети. Собственно, в данной статье я поделюсь своим опытом в реализации решения для данной задачи.
Сразу оговорюсь, что статья предназначена в большей мере для тех, кто имеет опыт Android-разработки, написал несколько приложений и хочет расширить свой кругозор, а также улучшить профессиональные навыки.
Какие возможные способы решения существуют?
- Android Network Service Discovery. Простой и эффективный способ обнаружения устройств. На Android Developer есть пошаговое руководство по подключению NSD, есть пример NsdChat, который можно скачать там же. Но есть один существенный минус — данный метод поддерживается только начиная с API Level 16, то есть с Android 4.1 Jelly Bean;
- Второе решение, предлагаемое нам на сайте Android Developer — Wi-Fi Peer-to-Peer. Проблема этого метода та же самая — поддерживается он только начиная с API Level 16;
- Есть странное решение, которое предлагается некоторыми программистами на Stack Overflow — самостоятельно сканировать локальную сеть на предмет наличия сервера. То есть проходить по всем адресам сети. Это уже сейчас звучит как странный велосипед, а теперь представьте, что порт нашего сервера назначается автоматически. Таким образом, сканирование даже самую небольшой сети становится достаточно долгой и трудоемкой задачей;
- Наконец, мы можем обратить внимание на Java-библиотеки и написать что-нибудь с их использованием. Например, JmDNS.
Последний способ выглядит вполне адекватным и, кажется, может обеспечить нас требуемой скоростью и удобством обнаружения устройств в сети для конечного пользователя.
Я вооружился JmDNS и решил попробовать соорудить несколько классов, которые по максимуму упростят написание описанных выше приложений. Но для начала пришлось немного повырезать дубликаты .class-файлов из jar-пакета JmDNS (проблема описана здесь):
Далее я взял исходный код NsdChat с Android Developer и изменил его служебный класс, который отвечает за инициализацию сокетов и организацию сетевого взаимодействия. Также я написал wrapper для JmDNS
Здесь размещены 4 основные функции для работы Network Discovery:
- startServer для создания сервера и регистрации соответствующего сервиса в локальной сети;
- findServers для поиска серверов;
- reset для окончания работы с Network Discovery и последующего освобождения ресурсов;
- wifiLock для запроса блокировки Wi-Fi.
В завершении я написал универсальный класс ConnectionWrapper для полноценной организации обнаружения, а также обмена сообщениями в локальной сети. Таким образом, создание сервера в конечном приложении выглядит следующим образом:
А вот и mServerHandler, использующийся для приема и обработки сообщений:
Отправка сообщений еще проще:
И, наконец, метод для обнаружения и подключения к серверу:
Как видите, все очень просто. А главное, все это работает в любой версии Android для максимум двух устройств. Но сделать так, чтобы это работало для условно неограниченного числа устройств очень легко, и очевидное решение придет к вам почти сразу после детального изучения класса Connection. Пусть это будет в качестве домашнего задания.
Ах, да, весь код доступен для изучения и использования всеми желающими в моем репозитории на GitHub.. И, конечно, не исключаю то, что некоторые вещи можно сделать лучше и проще, поэтому не стесняйтесь форкать и делать pull request’ы.
Источник