Чтение состояния сети

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, а затем отключается от нее. В этом примере также предполагается, что на устройстве включен параметр «Мобильные данные всегда включены».

График следующий:

  1. Когда приложение вызывает registerNetworkCallback() , обратный вызов немедленно получает вызовы от onAvailable() , onNetworkCapabilitiesChanged() и onLinkPropertiesChanged() для мобильной сети, поскольку доступна только эта сеть. Если доступна другая сеть, приложение также получает обратные вызовы для другой сети.

    Диаграмма состояний, показывающая событие обратного вызова сети регистрации и обратные вызовы, вызванные этим событием.
    Рисунок 1. Состояние приложения после вызова registerNetworkCallback() .

  2. Затем приложение вызывает registerDefaultNetworkCallback() . Обратный вызов сети по умолчанию начинает принимать вызовы onAvailable() , onNetworkCapabilitiesChanged() и onLinkPropertiesChanged() для мобильной сети, поскольку мобильная сеть является сетью по умолчанию. Если работает другая сеть, отличная от сети по умолчанию, приложение не сможет принимать вызовы для сети, отличной от сети по умолчанию.

    Диаграмма состояний, показывающая регистрацию события обратного вызова сети по умолчанию и обратных вызовов, вызванных этим событием.
    Рисунок 2. Состояние приложения после регистрации сети по умолчанию.

  3. Позже устройство подключается к (безлимитной) сети Wi-Fi. Обычный сетевой обратный вызов получает вызовы onAvailable() , onNetworkCapabilitiesChanged() и onLinkPropertiesChanged() для сети Wi-Fi.

    Диаграмма состояний, показывающая обратные вызовы, запускаемые при подключении приложения к новой сети.
    Рисунок 3. Состояние приложения после подключения к сети Wi-Fi без лимита.

  4. На этом этапе возможно, что проверка сети Wi-Fi займет некоторое время. В этом случае вызовы onNetworkCapabilitiesChanged() для обычного сетевого обратного вызова не включают возможность NET_CAPABILITY_VALIDATED . Через некоторое время он получает вызов onNetworkCapabilitiesChanged() , где новые возможности включают NET_CAPABILITY_VALIDATED . В большинстве случаев проверка происходит очень быстро.

    Когда сеть Wi-Fi проходит проверку, система предпочитает ее мобильной сети, главным образом потому, что она не имеет ограничений. Сеть Wi-Fi становится сетью по умолчанию, поэтому обратный вызов сети по умолчанию получает вызов onAvailable() , onNetworkCapabilitiesChanged() и onLinkPropertiesChanged() для сети Wi-Fi. Мобильная сеть переходит в фоновый режим, а обычный обратный вызов сети получает вызов onLosing() для мобильной сети.

    Поскольку в этом примере предполагается, что на этом устройстве мобильная передача данных всегда включена, мобильная сеть никогда не отключается. Если настройка выключена, то через некоторое время мобильная сеть отключается, и обычный сетевой обратный вызов получает вызов onLost() .

    Диаграмма состояний, показывающая обратные вызовы, запускаемые при проверке сетевого подключения Wi-Fi.
    Рисунок 4. Состояние приложения после проверки сети Wi-Fi.

  5. Еще позже устройство внезапно отключается от Wi-Fi, поскольку оно вышло за пределы зоны действия. Поскольку Wi-Fi отключается, обычный обратный вызов сети получает вызов onLost() для Wi-Fi. Поскольку мобильная сеть является новой сетью по умолчанию, обратный вызов сети по умолчанию принимает вызовы onAvailable() , onNetworkCapabilitiesChanged() и onLinkPropertiesChanged() для мобильной сети.

    Диаграмма состояний, показывающая обратные вызовы, запускаемые при потере подключения к сети Wi-Fi.
    Рисунок 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 , который будет вызываться при подключении сети.