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

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 предоставляют информацию обо всех атрибутах, известных системе о сети.

Объект 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 , если вашему приложению требуется только одноранговое 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 , которая должна быть вызвана при подключении к сети.