Работа с сетью android studio

Работа с сетью в 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.

Источник

Сетевая поддержка

2-й курс/Закрытая зона

Метки: ConnectivityManager , getBackgroundDataSetting() , java.net.InetAddress , android.net.TrafficStats

Быстрый старт

Как ни странно, но телефоны все дальше и дальше отдаляются от своей основной задачи — просто позвонить. Теперь устройство используется как платформа для сетевых игр, посещения сайтов, общения по Skype, ICQ и т.д. И поэтому телефону требуется обеспечить сетевую поддержку.

Мобильные устройства подключаются к Интернету при помощи 3G, Wi-Fi (в редких случаях и по кабелю), используя стандартные протоколы HTTP, HTTPS, TCP/IP, сокеты.

Основные моменты, на которые должен обратить внимание разработчик при реализации сетевой поддержки — обеспечение конфиденциальности, учет потребления заряда батареи, проверка доступности сети.

Android предоставляет разработчику все необходимые библиотеки для работы с сетью. Android использует для работы с сетью стандартные библиотеки Java , а также ряд своих библиотек.

В таблице приведены некоторые пакеты, относящиеся к сетевым возможностям, которые присутствуют в SDK Android:

java.net Содержит классы, связанные с сетевыми функциями, в том числе сокеты потоков и датаграмм, протокол IP, а также общие средства для работы с HTTP. Это многоцелевой ресурс для работы с сетями.
java.io Пакет не относится непосредственно к сетям. Его классы используются сокетами и соединениями, содержащимися в других пакетах Java. Они используются также для обмена с локальными файлами (что часто происходит при взаимодействии с сетью).
java.nio Содержит классы, которые служат буфером для определенных типов данных. Удобен для организации сетевой связи между двумя конечными точками средствами Java.
org.apache.* Набор пакетов, которые обеспечивают точный контроль и функции для HTTP-коммуникаций на основе Apache — популярного веб-сервера с открытым исходным кодом.
android.net Содержит дополнительные сокеты доступа к сети в дополнение к основным классам java.net.*. Этот пакет включает в себя класс URI, который часто используется в разработке приложений Android, не связанных с сетью.
android.net.http Содержит классы для работы с сертификатами SSL.
android.net.wifi Содержит классы для реализации всех аспектов WiFi (802.11 Wireless Ethernet) на платформе Android.

Важно, чтобы ваше приложение:

  • использовало сетевые сервисы только при необходимости (используйте локальное кэширование данных при первой возможности)
  • предупреждало пользователя при использовании личной информации
  • имело гибкие настройки включения и отключения различных функциональных возможностей без ущерба использования программы. Например, если уровни подгружаются из интернета, то первые несколько уровней должные быть зашиты в память программы
  • проверяло наличие сети и обрабатывало эту ситуацию
Читайте также:  Какие карты выбрать для андроида

Для настройки сетевой поддержки устройств используется приложение Настройки (Settings), в котором можно настроить различные режимы (Режим полёта, Wi-Fi, Мобильная сеть). Также там можно посмотреть сведения о беспроводной сети, её типе (CDMA, EDGE, GSM), уровень сигнала, состояние подключения к сотовой сети, состояние роуминга и др.

Вы вошли на сайт, как гость.
Необходимо зарегистрироваться, чтобы прочитать статью

Источник

Wi-Fi и много других аббревиатур. Как в Android приложении получить данные об узлах Wi-Fi и не опухнуть

Однажды мне понадобилось сканировать из Android приложения сети Wi-Fi и получать подробную выкладку данных о точках доступа.

Тут пришлось столкнуться с несколькими трудностями: в офф.документации Android многие описанные классы стали deprecated (API level > 26), что никак не было в ней отражено; описание некоторых вещей в документации минимально (например поле capabilities класса ScanResult на момент написания не описано почти никак, хотя содержит много важных данных). Третья сложность может заключаться в том, что при первой близости с Wi-Fi, отличной от чтения теории и настройки роутера по localhost, приходится иметь дело с рядом аббревиатур, которые кажутся понятными по отдельности. Но может быть не очевидно, как их соотнести и структурировать (суждение субъективно и зависит от предыдущего опыта).

В данной статье рассмотрено как из Android кода получить исчерпывающие данные о Wi-Fi окружении без NDK, хаков, а лишь с помощью Android API и понять, как их интерпретировать.

Не будем тянуть и начнем писать код.

1. Создаем проект

Заметка рассчитана на тех, кто больше одного раза создавал Android проект, поэтому подробности данного пункта опускаем. Код ниже будет представлен на языке Kotlin, minSdkVersion=23.

2. Разрешения на доступы

Для работы с Wi-Fi из приложения понадобится получить от пользователя несколько разрешений. В соответствии с документацией, для того, чтобы осуществить сканирование сети на устройствах с ОС версий после 8.0, помимо доступа к просмотру состояния сетевого окружения нужен либо доступ на изменение состояния модуля Wi-Fi устройства, либо доступ к координатам (примерным или точным). Начиная с версии 9.0 необходимо запросить у пользователя и то и то, и при этом явно запросить у пользователя включить службу определения местоположения. Не забываем галантно объяснять пользователю, что это прихоть компании Google, а не наше желание устроить за ним слежку 🙂

Итого, в AndroidManifest.xml добавим:

А в коде, в котором есть ссылка на текущую Activity:

3. Создаем BroadcastReceiver и подписываемся на события обновления данных о сканировании сетевого окружения Wi-Fi

Метод WiFiManager.startScan в документации помечен как depricated с версии API 28, но офф. guide предлагает использовать его.

Итого, получили список объектов ScanResult.

4. Смотрим на ScanResult и разбираемся в терминах

Посмотрим на некоторые поля этого класса и опишем, что они означают:

SSID — Service Set Identifier – это название сети

BSSID – Basic Service Set Identifier – MAC адрес сетевого адаптера (Wi-Fi точки)

level — Received Signal Strength Indicator [dBm (русское дБм) — Децибел, опорная мощность 1 мВт.] — Показатель уровня принимаемого сигнала. Принимает значение от 0 до -100, чем дальше от 0, тем больше мощности сигнала потерялось по пути от Wi-Fi точки к вашему устройству. Подробнее можно посмотреть например на Википедии. Здесь же расскажу, что с помощью Android класса WifiManager можно проградуировать уровень сигнала по шкале от отличного до ужасного с выбранным вами шагом:

frequency — частота работы точки Wi-Fi [Гц]. Помимо самой частоты вас может заинтересовать так называемый канал. У каждой точки есть своя рабочая чистота. На момент написания текста наиболее популярным диапозоном Wi-Fi точек является 2.4 GHz. Но, если быть точнее, точка передает информацию на ваш телефон на пронумерованной частоте, близкой к названной. Количество каналов и значения соответствующих частот стандартизованы. Это сделано для того, чтобы точки поблизости работали на разных частотах, тем самым не создавая помехи друг другу и взаимно не понижая скорость и качество передачи. При этом точки работают не на одной частоте, а на диапазоне частот (пареметр channelWidth), называемом шириной канала. То есть точки, работающие на соседних (и не только на соседних, а даже на 3 от себя) каналах создают друг другу помехи. Вам может пригодится этот незамысловатый код, который позволяет вычислить номер канала по значению частоты для точек с частотой 2.4 и 5 Ghz:

capabilities — наиболее интересное поле для анализа, работа с которым потребовало много времени. Тут в строку записываются «возможности» точки. При этом подробности интерпритации строки в документации можно не искать. Вот несколько примеров того, что может лежать в этой строке:

Читайте также:  Bitlife mafia update android

5. Разбираемся в аббревиатурах и парсим capabilities

Стоит упомянуть, что классы пакета android.net.wifi.* использует под капотом linux-утилиту wpa_supplicant и результат вывода в поле capabilities является копией поля flags при сканировании.

Будем действовать последовательно. Рассмотрим сначала вывод такого формата, при котором внутри скобок элементы отделены знаком «-«:

Первое значение описывает т.н. метод аутентификации (authentication). То есть, какую последовательность действий должны произвести устройство и точка доступа, чтобы точка доступа позволила собой пользоваться и каким образом шифровать полезную нагрузку. На момент написания поста самые частые варианты это WPA и WPA2, при котором либо каждое подключаемое устройство напрямую, либо через т.н. RADIUS-сервер (WPA-Enterprice) предоставляет пароль по зашифрованному каналу. Скорее всего у вас дома точка доступа предоставляет подключение по этой схеме. Отличие второй версии от первой в болеее стойком шифре: AES против небезопасного TKIP. Также постепенно внедряется WPA3, более сложный и продвинутый. Теоритически может встретиться вариант с enterprice-решением CCKM (Cisco Centralized Key Managment), но мне так и не встретился.

Точка доступа могла быть настроена на аутентификацию по MAC-адресу. Или, если точка доступа предоставляет данные по устаревшему алгоритму WEP, то аутентификации фактически нет (секретный ключ тут и является ключом шифрования). Такие варианты отнесем к типу OTHER.
Ещё есть полюбившийся в общественных wi-fi метод со скрытым Captive Portal Detection — запрос аутентификации через браузер. Такие точки доступа выглядят для сканера как открытые (какими с точки зраения физического подключения и являются). Поэтому отнесем их к типу OPEN.

Второе значение можно обозначить как алгоритм использования ключей (key management). Является параметром метода аутентификации, о котором написано выше. Говорит о том, как именно происходит обмен ключами шифрования. Рассмотрим возможные варианты. EAP — используется в упомянутом WPA-Enterprice, использует базу данных для сверки введеных аутентификационных данных. SAE — используется в продвинутом WPA3, более устойчива к перебору. PSK — самый частый вариант, подразумевает ввод пароля и его передачу в зашифрованном виде. IEEE8021X — по международному стандарту (отличному от поддержанным семейством WPA). OWE (Opportunistic Wireless Encryption) является расширением стандарта IEEE 802.11, для точек, которые мы отнесли к типу OPEN. OWE обеспечивает безопасность данных, передаваемых по незащищенной сети, за счет их шифрования. Также возможен варинант когда ключей доступа нет, назовем такой вариант NONE.

Третьим параметром является т.н. метод шифрования (encryption schemes) — как именно используется шифр для зашиты передаваемых данных. Перечислим варианты. WEP — использует поточный шифр RC4, секретный ключ является ключом шифрования, что в мире современной криптографии считается неприемлемым. TKIP — используется в WPA, CKIP — в WPA2. TKIP+CKIP — может быть указан в точках умеющих WPA и WPA2 для обратной совместимости.

Вместо трех элементов можно встретить одинокую пометку WEP:

Как мы обсудили выше, этого достаточно чтобы не конкретизировать алгоритм использования ключей, которого нет, и метода шифрования, которое одно по-умолчанию.

Теперь рассмотрим такую скобочку:

Это режим работы Wi-Fi или топология сетей Wi-Fi. Вам может встретиться Режим BSS (Basic Service Set) — когда есть одна точка доступа, через которую общаются подключенные устройства. Можно встретить в локальных сетях. Как правило точки доступа нужны для того, чтобы соединять устройства из разных локальных сетей, поэтому они являются частью Extended Service Sets — ESS. Тип IBSSs (Independent Basic Service Sets) говорит о том, что устройство является частью Peer-to-Peer сети.

Ещё может попасться флаг WPS:

WPS (Wi-Fi Protected Setup) — протокол полуавтоматической инициализации сети Wi-Fi. Для инициализации пользователь либо вводит 8-символьный пароль, либо зажимает кнопку на роутере. Если ваша точка доступа относится к первому типу и этот флажок высветился напротив имени вашей точки доступа, вам настоятельно рекомендуется зайти в админку и отключить доступ по WPS. Дело в том, что часто 8-значный PIN можно узнать по MAC-адресу, либо перебрать за обозримое время, чем кто-то нечистый на руку сможет воспользоваться.

6. Создаем модель и функцию парсинга

На основе того, что выяснили выше опишем data-классами то, что получилось:

Теперь напишем функцию, которая будет парсить поле capabilities:

8. Смотрим результат

Посканирую сеть и покажу, что получилось. Показаны результаты простого вывода через Log.d:

Неосвещенным остался вопрос подключения к сети из кода приложения. Скажу только, что для того, чтобы считать сохраненные пароли ОС мобильного устройства, нужны root-права и готовность порыться в файловой системе чтобы прочитать wpa_supplicant.conf. Если логика приложения предполагает ввод пароля извне, подключение можно осуществить через класс android.net.wifi.WifiManager.

Спасибо Егору Пономареву за ценные дополнения.

Если считаете, что нужно что-то добавить или исправить, пишите в комментарии 🙂

Источник

Оцените статью