Android позволяет приложениям узнавать о динамических изменениях в подключении. Используйте следующие классы для отслеживания изменений подключения и реагирования на них:
-
ConnectivityManager
сообщает вашему приложению о состоянии подключения в системе. - Класс
Network
представляет одну из сетей, к которым подключено устройство. Вы можете использовать объектNetwork
в качестве ключа для сбора информации о сети с помощьюConnectivityManager
или для привязки сокетов в сети. Когда сеть отключается, объектNetwork
перестает быть доступным для использования. Даже если устройство позже снова подключится к тому же устройству, новый объектNetwork
представляет новую сеть. - Объект
LinkProperties
содержит информацию о ссылке на сеть, например список DNS-серверов, локальных IP-адресов и сетевых маршрутов, установленных для сети. - Объект
NetworkCapabilities
содержит информацию о свойствах сети, таких как транспорт (Wi-Fi, мобильный телефон, Bluetooth) и возможности сети. Например, вы можете запросить объект, чтобы определить, способна ли сеть отправлять MMS, находится ли за авторизованным порталом или измеряется.
Приложения, заинтересованные в текущем состоянии подключения в любой момент времени, могут вызывать методы ConnectivityManager
чтобы узнать, какой тип сети доступен. Эти методы полезны для отладки и периодического просмотра моментального снимка подключения, доступного в любой момент времени.
Однако синхронные методы ConnectivityManager
не сообщают вашему приложению о том, что происходит после вызова, поэтому они не позволяют обновлять пользовательский интерфейс. Они также не могут корректировать поведение приложения в зависимости от отключения сети или изменения сетевых возможностей.
Возможности подключения могут измениться в любое время, и большинству приложений необходимо всегда иметь актуальное представление о состоянии сети на устройстве. Приложения могут зарегистрировать обратный вызов с помощью ConnectivityManager
чтобы получать уведомления об изменениях, которые важны для приложения. Используя обратный вызов, ваше приложение может немедленно реагировать на любые важные изменения в подключении, не прибегая к дорогостоящим опросам, которые могут пропустить быстрые обновления.
Использование NetworkCallback
и других способов узнать о состоянии подключения устройства не требует какого-либо специального разрешения. Однако для некоторых сетей требуются особые разрешения. Например, могут существовать сети с ограниченным доступом, недоступные для приложений. Для привязки к фоновой сети требуется разрешение CHANGE_NETWORK_STATE
. А для выполнения некоторых вызовов могут потребоваться особые разрешения. Подробности смотрите в документации по каждому вызову.
Получить мгновенное состояние
Устройство на базе Android может поддерживать множество соединений одновременно. Чтобы получить информацию о текущем состоянии сети, сначала получите экземпляр ConnectivityManager
:
Котлин
val connectivityManager = getSystemService(ConnectivityManager::class.java)
Ява
ConnectivityManager connectivityManager = getSystemService(ConnectivityManager.class);
Затем используйте этот экземпляр, чтобы получить ссылку на текущую сеть по умолчанию для вашего приложения:
Котлин
val currentNetwork = connectivityManager.getActiveNetwork()
Ява
Network currentNetwork = connectivityManager.getActiveNetwork();
Ссылаясь на сеть, ваше приложение может запрашивать информацию о ней:
Котлин
val caps = connectivityManager.getNetworkCapabilities(currentNetwork) val linkProperties = connectivityManager.getLinkProperties(currentNetwork)
Ява
NetworkCapabilities caps = connectivityManager.getNetworkCapabilities(currentNetwork); LinkProperties linkProperties = connectivityManager.getLinkProperties(currentNetwork);
Для получения более полезных функций зарегистрируйте NetworkCallback
. Дополнительные сведения о регистрации сетевых обратных вызовов см. в разделе Прослушивание сетевых событий .
NetworkCapabilities и LinkProperties
Объекты NetworkCapabilities
и LinkProperties
предоставляют информацию обо всех атрибутах сети, известных системе.
Объект LinkProperties
знает о маршрутах, адресах ссылок, имени интерфейса, информации о прокси-сервере (если есть) и DNS-серверах. Вызовите соответствующий метод объекта LinkProperties
, чтобы получить необходимую информацию.
Объект NetworkCapabilities
инкапсулирует информацию о сетевых транспортах и их возможностях .
Транспорт — это абстракция физической среды, в которой работает сеть. Типичными примерами транспорта являются Ethernet, Wi-Fi и мобильная связь. VPN и одноранговый Wi-Fi также могут быть транспортными средствами. На Android в сети может одновременно работать несколько транспортов. Примером этого является VPN, работающая как через Wi-Fi, так и через мобильные сети. VPN имеет Wi-Fi, мобильный и VPN-транспорт. Чтобы узнать, есть ли в сети определенный транспорт, используйте метод NetworkCapabilities.hasTransport(int)
с одной из констант NetworkCapabilities.TRANSPORT_*
.
Возможность описывает свойство сети. Примеры возможностей включают MMS
, NOT_METERED
и INTERNET
. Сеть с возможностью MMS может отправлять и получать сообщения службы мультимедийных сообщений, а сеть без этой возможности — нет. Сеть с возможностью NOT_METERED
не взимает с пользователя плату за данные. Ваше приложение может проверить наличие соответствующих возможностей с помощью метода NetworkCapabilities.hasCapability(int)
с одной из констант NetworkCapabilities.NET_CAPABILITY_*
.
Наиболее полезные константы NET_CAPABILITY_*
включают:
NET_CAPABILITY_INTERNET
: указывает, что сеть настроена для доступа в Интернет. Речь идет о настройке , а не о фактической возможности доступа к общедоступным серверам. Например, сеть может быть настроена для доступа в Интернет, но при этом она будет подчиняться авторизованному порталу.Мобильная сеть оператора обычно имеет возможность
INTERNET
, а локальная сеть P2P Wi-Fi обычно ее не имеет. Для фактического подключения см.NET_CAPABILITY_VALIDATED
.NET_CAPABILITY_NOT_METERED
: указывает, что сеть не измеряется. Сеть классифицируется как лимитированная, если пользователь чувствителен к интенсивному использованию данных по этому соединению из-за денежных затрат, ограничений данных или проблем с производительностью батареи.NET_CAPABILITY_NOT_VPN
: указывает, что сеть не является виртуальной частной сетью.NET_CAPABILITY_VALIDATED
: указывает, что сеть обеспечивает фактический доступ к общедоступному Интернету при его проверке. Сеть за авторизованным порталом или сеть, которая не обеспечивает разрешение доменных имен, не имеет такой возможности. Это самое близкое, что система может сказать о сети, фактически предоставляющей доступ, хотя проверенная сеть в принципе может подвергаться IP-фильтрации или внезапной потере соединения из-за таких проблем, как плохой сигнал.NET_CAPABILITY_CAPTIVE_PORTAL
: указывает, что в сети имеется портал авторизации при ее проверке.
Существуют и другие возможности, которые могут быть интересны более специализированным приложениям. Для получения дополнительной информации прочтите определения параметров в NetworkCapabilities.hasCapability(int)
.
Возможности сети могут измениться в любое время. Когда система обнаруживает авторизованный портал, она отображает уведомление, приглашающее пользователя войти в систему. Пока это происходит, сеть имеет возможности NET_CAPABILITY_INTERNET
и NET_CAPABILITY_CAPTIVE_PORTAL
но не возможность NET_CAPABILITY_VALIDATED
.
Когда пользователь выполняет действие и входит на страницу авторизованного портала, устройство получает доступ к общедоступному Интернету, а сеть получает возможность NET_CAPABILITY_VALIDATED
и теряет возможность NET_CAPABILITY_CAPTIVE_PORTAL
.
Аналогично, транспорты сети могут меняться динамически. Например, VPN может перенастроиться для использования только что появившейся более быстрой сети, например, переключиться с мобильного телефона на Wi-Fi для своей базовой сети. В этом случае сеть теряет транспорт TRANSPORT_CELLULAR
и получает транспорт TRANSPORT_WIFI
, сохраняя при этом транспорт TRANSPORT_VPN
.
Слушайте сетевые события
Чтобы узнать о сетевых событиях, используйте класс NetworkCallback
вместе с ConnectivityManager.registerDefaultNetworkCallback(NetworkCallback)
и ConnectivityManager.registerNetworkCallback(NetworkCallback)
. Эти два метода служат разным целям.
Все приложения Android имеют сеть по умолчанию, которая определяется системой. Система обычно предпочитает сети без счетчиков лимитированным и более быстрые сети медленным.
Когда приложение выдает сетевой запрос, например с помощью HttpsURLConnection
, система удовлетворяет этот запрос, используя сеть по умолчанию. Приложения также могут отправлять трафик в другие сети. Подробную информацию смотрите в разделе о дополнительных сетях .
Сеть, установленная в качестве сети по умолчанию, может измениться в любой момент в течение жизненного цикла приложения. Типичным примером является устройство, находящееся в зоне действия известной, активной, безлимитной и более быстрой, чем мобильная, точки доступа Wi-Fi. Устройство подключается к этой точке доступа и переключает сеть по умолчанию для всех приложений на новую сеть Wi-Fi.
Когда новая сеть становится сетью по умолчанию, любое новое соединение, открываемое приложением, использует эту сеть. В какой-то момент все оставшиеся соединения в предыдущей сети по умолчанию будут принудительно разорваны. Если приложению важно знать, когда меняется сеть по умолчанию, оно регистрирует обратный вызов сети по умолчанию следующим образом:
Котлин
connectivityManager.registerDefaultNetworkCallback(object : ConnectivityManager.NetworkCallback() { override fun onAvailable(network : Network) { Log.e(TAG, "The default network is now: " + network) } override fun onLost(network : Network) { Log.e(TAG, "The application no longer has a default network. The last default network was " + network) } override fun onCapabilitiesChanged(network : Network, networkCapabilities : NetworkCapabilities) { Log.e(TAG, "The default network changed capabilities: " + networkCapabilities) } override fun onLinkPropertiesChanged(network : Network, linkProperties : LinkProperties) { Log.e(TAG, "The default network changed link properties: " + linkProperties) } })
Ява
connectivityManager.registerDefaultNetworkCallback(new ConnectivityManager.NetworkCallback() { @Override public void onAvailable(Network network) { Log.e(TAG, "The default network is now: " + network); } @Override public void onLost(Network network) { Log.e(TAG, "The application no longer has a default network. The last default network was " + network); } @Override public void onCapabilitiesChanged(Network network, NetworkCapabilities networkCapabilities) { Log.e(TAG, "The default network changed capabilities: " + networkCapabilities); } @Override public void onLinkPropertiesChanged(Network network, LinkProperties linkProperties) { Log.e(TAG, "The default network changed link properties: " + linkProperties); } });
Когда новая сеть становится сетью по умолчанию, приложение получает вызов onAvailable(Network)
для новой сети. Реализуйте onCapabilitiesChanged(Network,NetworkCapabilities)
, onLinkPropertiesChanged(Network,LinkProperties)
или оба, чтобы соответствующим образом реагировать на изменения в подключении.
Для обратного вызова, зарегистрированного с помощью registerDefaultNetworkCallback()
, onLost()
означает, что сеть потеряла статус сети по умолчанию. Возможно, он отключен.
Хотя вы можете узнать о транспортах, которые использует сеть по умолчанию, запросив NetworkCapabilities.hasTransport(int)
, это плохой прокси-сервер для определения пропускной способности или измеренности сети. Ваше приложение не может предполагать, что Wi-Fi всегда не лимитирован и всегда обеспечивает лучшую пропускную способность, чем мобильная связь.
Вместо этого используйте NetworkCapabilities.getLinkDownstreamBandwidthKbps()
для измерения пропускной способности и NetworkCapabilites.hasCapability(int)
с аргументами NET_CAPABILITY_NOT_METERED
для определения измеренности. Дополнительные сведения см. в разделе о NetworkCapabilities и LinkProperties .
По умолчанию методы обратного вызова вызываются в потоке подключения вашего приложения, который представляет собой отдельный поток, используемый ConnectivityManager
. Если вашей реализации обратных вызовов требуется дополнительная работа, вызовите их в отдельном рабочем потоке, используя вариант ConnectivityManager.registerDefaultNetworkCallback(NetworkCallback, Handler)
.
Отмените регистрацию обратного вызова, если он вам больше не нужен, вызвав ConnectivityManager.unregisterNetworkCallback(NetworkCallback)
. onPause()
вашего основного действия — хорошее место для этого, особенно если вы зарегистрируете обратный вызов в onResume()
.
Дополнительные сети
Хотя сеть по умолчанию является единственной подходящей сетью для большинства приложений, некоторым приложениям могут быть интересны другие доступные сети. Чтобы узнать об этом, приложения создают NetworkRequest
соответствующий их потребностям, и вызывают ConnectivityManager.registerNetworkCallback(NetworkRequest, NetworkCallback)
.
Этот процесс аналогичен прослушиванию сети по умолчанию. Однако, хотя в любой момент времени к приложению может применяться только одна сеть по умолчанию, эта версия позволяет вашему приложению видеть все доступные сети одновременно, поэтому вызов onLost(Network)
означает, что сеть отключена навсегда, а не это больше не значение по умолчанию.
Приложение создает NetworkRequest
, чтобы сообщить ConnectivityManager
, какие сети оно хочет прослушивать. В следующем примере показано, как создать NetworkRequest
для приложения, которому интересны только безлимитные подключения к Интернету:
Котлин
val request = NetworkRequest.Builder() .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED) .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) .build() connectivityManager.registerNetworkCallback(request, myNetworkCallback)
Ява
NetworkRequest request = new NetworkRequest.Builder() .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED) .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) .build(); connectivityManager.registerNetworkCallback(request, myNetworkCallback);
Это означает, что ваше приложение узнает обо всех изменениях, касающихся любой нерегулируемой сети в системе.
Что касается обратного вызова сети по умолчанию, существует версия registerNetworkCallback(NetworkRequest, NetworkCallback, Handler)
, которая принимает Handler
поэтому не загружает поток Connectivity
вашего приложения.
Вызовите ConnectivityManager.unregisterNetworkCallback(NetworkCallback)
когда обратный вызов больше не актуален. Приложение может одновременно регистрировать несколько сетевых обратных вызовов.
Для удобства объект NetworkRequest
содержит общие возможности, необходимые большинству приложений, включая следующие:
При написании приложения проверьте значения по умолчанию, чтобы увидеть, соответствуют ли они вашему варианту использования, и очистите их, если вы хотите, чтобы ваше приложение уведомлялось о сетях, которые не имеют этих возможностей. С другой стороны, добавьте возможности, чтобы избежать вызовов при любых изменениях подключения в сетях, с которыми ваше приложение не взаимодействует.
Например, если вашему приложению необходимо отправлять MMS-сообщения, добавьте NET_CAPABILITY_MMS
в NetworkRequest
, чтобы вам не сообщали обо всех сетях, которые не могут отправлять MMS-сообщения. Добавьте TRANSPORT_WIFI_AWARE
, если ваше приложение заинтересовано только в P2P-подключении Wi-Fi. NET_CAPABILITY_INTERNET
и NET_CAPABILITY_VALIDATED
полезны, если вас интересует возможность передачи данных с сервера в Интернете.
Пример последовательности обратного вызова
В этом разделе описывается последовательность обратных вызовов, которые может получить приложение, если оно регистрирует как обратный вызов по умолчанию, так и обычный обратный вызов на устройстве с возможностью подключения к мобильной сети. В этом примере устройство подключается к исправной точке доступа Wi-Fi, а затем отключается от нее. В этом примере также предполагается, что на устройстве включен параметр «Мобильные данные всегда включены».
График следующий:
Когда приложение вызывает
registerNetworkCallback()
, обратный вызов немедленно получает вызовы отonAvailable()
,onNetworkCapabilitiesChanged()
иonLinkPropertiesChanged()
для мобильной сети, поскольку доступна только эта сеть. Если доступна другая сеть, приложение также получает обратные вызовы для другой сети.
Рисунок 1. Состояние приложения после вызоваregisterNetworkCallback()
.Затем приложение вызывает
registerDefaultNetworkCallback()
. Обратный вызов сети по умолчанию начинает принимать вызовыonAvailable()
,onNetworkCapabilitiesChanged()
иonLinkPropertiesChanged()
для мобильной сети, поскольку мобильная сеть является сетью по умолчанию. Если работает другая сеть, отличная от сети по умолчанию, приложение не сможет принимать вызовы для сети, отличной от сети по умолчанию.
Рисунок 2. Состояние приложения после регистрации сети по умолчанию.Позже устройство подключается к (безлимитной) сети Wi-Fi. Обычный сетевой обратный вызов получает вызовы
onAvailable()
,onNetworkCapabilitiesChanged()
иonLinkPropertiesChanged()
для сети Wi-Fi.
Рисунок 3. Состояние приложения после подключения к сети Wi-Fi без ограничений.На этом этапе возможно, что проверка сети Wi-Fi займет некоторое время. В этом случае вызовы
onNetworkCapabilitiesChanged()
для обычного сетевого обратного вызова не включают возможностьNET_CAPABILITY_VALIDATED
. Через некоторое время он получает вызовonNetworkCapabilitiesChanged()
, где новые возможности включаютNET_CAPABILITY_VALIDATED
. В большинстве случаев проверка происходит очень быстро.Когда сеть Wi-Fi проходит проверку, система предпочитает ее мобильной сети, главным образом потому, что она не имеет ограничений. Сеть Wi-Fi становится сетью по умолчанию, поэтому обратный вызов сети по умолчанию получает вызов
onAvailable()
,onNetworkCapabilitiesChanged()
иonLinkPropertiesChanged()
для сети Wi-Fi. Мобильная сеть переходит в фоновый режим, а обычный обратный вызов сети получает вызовonLosing()
для мобильной сети.Поскольку в этом примере предполагается, что на этом устройстве мобильная передача данных всегда включена, мобильная сеть никогда не отключается. Если настройка отключена, то через некоторое время мобильная сеть отключается, и обычный сетевой обратный вызов получает вызов
onLost()
.
Рисунок 4. Состояние приложения после проверки сети Wi-Fi.Еще позже устройство внезапно отключается от Wi-Fi, поскольку оно вышло за пределы зоны действия. Поскольку Wi-Fi отключается, обычный обратный вызов сети получает вызов
onLost()
для Wi-Fi. Поскольку мобильная сеть является новой сетью по умолчанию, обратный вызов сети по умолчанию принимает вызовыonAvailable()
,onNetworkCapabilitiesChanged()
иonLinkPropertiesChanged()
для мобильной сети.
Рисунок 5. Состояние приложения после отключения от сети Wi-Fi.
Если настройка «Мобильные данные всегда включены» отключена, то при отключении Wi-Fi устройство пытается повторно подключиться к мобильной сети. Картина аналогична, но с небольшой дополнительной задержкой для вызовов onAvailable()
, а обычный сетевой обратный вызов также получает вызовы onAvailable()
, onNetworkCapabilitiesChanged()
и onLinkPropertiesChanged()
поскольку мобильные устройства становятся доступными.
Ограничения на использование сети для передачи данных
Возможность видеть сеть с помощью обратного вызова сети не означает, что ваше приложение может использовать сеть для передачи данных. Некоторые сети не обеспечивают подключение к Интернету, а некоторые сети могут быть ограничены доступом к привилегированным приложениям. Чтобы проверить подключение к Интернету, см. NET_CAPABILITY_INTERNET
и NET_CAPABILITY_VALIDATED
.
Использование фоновых сетей также подлежит проверке разрешений. Если ваше приложение хочет использовать фоновую сеть, ему необходимо разрешение CHANGE_NETWORK_STATE
.
Приложения с этим разрешением позволяют системе попытаться подключить неактивную сеть, например мобильную сеть, когда устройство подключено к сети Wi-Fi. Такое приложение вызывает ConnectivityManager.requestNetwork(NetworkRequest, NetworkCallback)
с NetworkCallback
, который будет вызываться при подключении сети.