Odczytywanie stanu sieci

Android umożliwia aplikacjom śledzenie dynamicznych zmian w łączności. Aby śledzić zmiany w połączeniach i na nie reagować, użyj tych klas:

  • ConnectivityManager informuje aplikację o stanie łączności w systemie.
  • Klasa Network reprezentuje jedną z sieci, do których jest podłączone urządzenie. Obiekt Network możesz używać jako klucza do zbierania informacji o sieci za pomocą funkcji ConnectivityManager lub do wiązania gniazd w sieci. Po rozłączeniu sieci obiekt Network przestanie być użyteczny. Nawet jeśli urządzenie później ponownie połączy się z tym samym urządzeniem, nowy obiekt Network reprezentuje nową sieć.
  • Obiekt LinkProperties zawiera informacje o połączeniu sieci, takie jak lista serwerów DNS, adresy IP lokalne i trasy sieciowe zainstalowane w ramach sieci.
  • Obiekt NetworkCapabilities zawiera informacje o właściwościach sieci, takie jak transporty (Wi-Fi, komórkowy, Bluetooth) i możliwości sieci. Możesz na przykład wysłać zapytanie do obiektu, aby określić, czy sieć jest w stanie wysyłać wiadomości MMS, czy jest chroniona przez portal przechwytujący lub czy jest naliczana taryfa.

Aplikacje, które w danym momencie chcą znać bieżący stan połączenia, mogą wywoływać metody ConnectivityManager, aby dowiedzieć się, jaka sieć jest dostępna. Metody te są pomocne w debugowaniu i pozwalają od czasu do czasu przejrzeć podsumowanie połączeń dostępnych w danym momencie.

Jednak synchroniczne metody ConnectivityManager nie informują aplikacji o tym, co dzieje się po wywołaniu, więc nie pozwalają na aktualizację interfejsu użytkownika. Nie mogą też dostosowywać zachowania aplikacji na podstawie odłączenia sieci lub zmiany jej możliwości.

Łączność może się zmienić w dowolnym momencie, a większość aplikacji musi mieć aktualny widok stanu sieci na urządzeniu. Aplikacje mogą zarejestrować wywołanie zwrotne za pomocą ConnectivityManager, aby otrzymywać powiadomienia o zmianach, które są dla niej istotne. Dzięki wywołaniu zwrotnemu aplikacja może natychmiast reagować na każdą istotną zmianę w połączeniu bez konieczności korzystania z drogiego pollingu, który może pomijać szybkie aktualizacje.

Korzystanie z funkcji NetworkCallback i innych sposobów sprawdzania stanu połączeń urządzenia nie wymaga żadnego szczególnego uprawnienia. Niektóre sieci wymagają jednak specjalnych uprawnień. Na przykład mogą być sieci z ograniczonym dostępem niedostępne dla aplikacji. Powiązanie z siecią w tle wymaga uprawnienia CHANGE_NETWORK_STATE. Niektóre wywołania mogą wymagać określonych uprawnień do uruchomienia. Szczegółowe informacje o każdym wywołaniu znajdziesz w odpowiedniej dokumentacji.

Pobieranie stanu chwilkowego

Urządzenie z Androidem może utrzymywać wiele połączeń jednocześnie. Aby uzyskać informacje o bieżącym stanie sieci, najpierw pobierz instancję ConnectivityManager:

Kotlin

val connectivityManager = getSystemService(ConnectivityManager::class.java)

Java

ConnectivityManager connectivityManager = getSystemService(ConnectivityManager.class);

Następnie użyj tej instancji, aby uzyskać odwołanie do bieżącej domyślnej sieci aplikacji:

Kotlin

val currentNetwork = connectivityManager.getActiveNetwork()

Java

Network currentNetwork = connectivityManager.getActiveNetwork();

Gdy aplikacja odwołuje się do sieci, może poprosić o informacje o niej:

Kotlin

val caps = connectivityManager.getNetworkCapabilities(currentNetwork)
val linkProperties = connectivityManager.getLinkProperties(currentNetwork)

Java

NetworkCapabilities caps = connectivityManager.getNetworkCapabilities(currentNetwork);
LinkProperties linkProperties = connectivityManager.getLinkProperties(currentNetwork);

Aby mieć dostęp do bardziej przydatnych funkcji, zarejestruj NetworkCallback. Więcej informacji o rejestrowaniu wywołań zwrotnych sieci znajdziesz w artykule o nasłuchiwaniu zdarzeń sieciowych.

NetworkCapabilities i LinkProperties

Obiekty NetworkCapabilities i LinkProperties zawierają informacje o wszystkich atrybutach, które system zna w przypadku sieci.

Obiekt LinkProperties zna trasy, adresy linków, nazwę interfejsu, informacje o serwerze proxy (jeśli występują) i serwery DNS. Aby pobrać potrzebne informacje, wywołaj odpowiednią metodę obiektu LinkProperties.

Obiekt NetworkCapabilities zawiera informacje o transportach sieci i ich możliwościach.

Transport to abstrakcja ośrodka fizycznego, przez który działa sieć. Typowymi przykładami transportu są Ethernet, Wi-Fi i mobilne. Do transportu można też wykorzystać VPN-y i Wi-Fi typu peer-to-peer. Na Androidzie sieć może mieć jednocześnie wiele transportów. Przykładem może być sieć VPN działająca zarówno przez Wi-Fi, jak i sieci komórkowe. Sieć VPN ma transporty Wi-Fi, komórkowy i VPN. Aby sprawdzić, czy sieć ma określony transport, użyj metody NetworkCapabilities.hasTransport(int) z jedną z konstant NetworkCapabilities.TRANSPORT_*.

Umiejętność opisuje właściwość sieci. Przykładowe możliwości: MMS, NOT_METERED i INTERNET. Sieć z możliwością wysyłania i odbierania wiadomości MMS może wysyłać i odbierać wiadomości MMS, a sieć bez tej funkcji nie może tego robić. Sieć z funkcją NOT_METERED nie obciąża użytkownika opłatami za dane. Aplikacja może sprawdzić, czy urządzenie ma odpowiednie możliwości, za pomocą metody NetworkCapabilities.hasCapability(int) z jedną z konstant NetworkCapabilities.NET_CAPABILITY_*.

Najbardziej przydatne stałe NET_CAPABILITY_* to:

  • NET_CAPABILITY_INTERNET: wskazuje, że sieć jest skonfigurowana do korzystania z internetu. Chodzi o konfigurację, a nie o rzeczywistą możliwość dotarcia do serwerów publicznych. Na przykład można skonfigurować sieć tak, aby łączyć się z internetem, ale podlegać portalu przechwytującego.

    Sieć komórkowa operatora zwykle ma funkcję INTERNET, a lokalna sieć P2P – Wi-Fi – nie. Informacje o rzeczywistej łączności znajdziesz w artykule NET_CAPABILITY_VALIDATED.

  • NET_CAPABILITY_NOT_METERED: oznacza, że sieć nie jest objęta pomiarem użycia danych. Sieć jest klasyfikowana jako z limitem, gdy użytkownik jest wrażliwy na duże zużycie danych w ramach tego połączenia z powodu kosztów, ograniczeń dotyczących danych lub problemów z wydajnością baterii.

  • NET_CAPABILITY_NOT_VPN: oznacza, że sieć nie jest wirtualną siecią prywatną.

  • NET_CAPABILITY_VALIDATED: wskazuje, że sieć zapewnia rzeczywisty dostęp do publicznego internetu podczas sprawdzania. Sieć za portalem internetowym lub sieć, która nie zapewnia rozpoznawania nazw domen, nie ma tej funkcji. To najbliższe, co system może powiedzieć o sieci, która faktycznie zapewnia dostęp, chociaż zweryfikowana sieć może nadal podlegać filtrowaniu na podstawie adresu IP lub nagłej utraty łączności z powodu problemów takich jak słaby sygnał.

  • NET_CAPABILITY_CAPTIVE_PORTAL: wskazuje, że sieć ma portal przechwytujący, gdy jest sprawdzany.

Istnieją też inne funkcje, które mogą zainteresować bardziej wyspecjalizowane aplikacje. Więcej informacji znajdziesz w definicjach parametrów w artykule NetworkCapabilities.hasCapability(int).

Możliwości sieci mogą się zmieniać w każdej chwili. Gdy system wykryje portal, wyświetla powiadomienie zapraszające użytkownika do zalogowania się. Podczas tego procesu sieć ma dostęp do funkcji NET_CAPABILITY_INTERNETNET_CAPABILITY_CAPTIVE_PORTAL, ale nie do funkcji NET_CAPABILITY_VALIDATED.

Gdy użytkownik podejmie działanie i zaloguje się na stronie portalu przechwytującego, urządzenie uzyska dostęp do publicznego internetu, a sieć uzyska funkcję NET_CAPABILITY_VALIDATED i straci funkcję NET_CAPABILITY_CAPTIVE_PORTAL.

Transport w sieci również może się dynamicznie zmieniać. Sieć VPN może na przykład zmienić konfigurację, aby korzystać z szybszej sieci, która właśnie się pojawiła, np. przełączyć się z sieci komórkowej na Wi-Fi. W tym przypadku sieć traci transport TRANSPORT_CELLULAR i zyskuje transport TRANSPORT_WIFI, zachowując transport TRANSPORT_VPN.

Nasłuchiwanie zdarzeń sieciowych

Aby uzyskać informacje o zdarzeniach sieciowych, użyj klasy NetworkCallback razem z ConnectivityManager.registerDefaultNetworkCallback(NetworkCallback) i ConnectivityManager.registerNetworkCallback(NetworkCallback). Te 2 metody służą różnym celom.

Wszystkie aplikacje na Androida mają sieć domyślną, która jest określana przez system. System zwykle preferuje sieci bez limitu danych przed sieciami z limitem danych oraz szybsze sieci przed wolniejszymi.

Gdy aplikacja wysyła żądanie sieciowe, na przykład HttpsURLConnection, system spełnia to żądanie, korzystając z domyślnej sieci. Aplikacje mogą też wysyłać ruch w innych sieciach. Więcej informacji znajdziesz w sekcji dotyczącej dodatkowych sieci.

Sieć ustawiona jako sieć domyślna może się zmienić w dowolnym momencie podczas działania aplikacji. Typowym przykładem jest urządzenie znajdujące się w zasięgu znanego, aktywnego, niepomiarowego i szybszego niż komórkowy punktu dostępu Wi-Fi. Urządzenie łączy się z tym punktem dostępu i przełącza domyślną sieć dla wszystkich aplikacji na nową sieć Wi-Fi.

Gdy nowa sieć stanie się siecią domyślną, każde nowe połączenie otwierane przez aplikację będzie używać tej sieci. W pewnym momencie wszystkie pozostałe połączenia w poprzedniej sieci domyślnej zostaną przymusowo zakończone. Jeśli aplikacja musi wiedzieć, kiedy zmienia się sieć domyślna, rejestruje wywołanie zwrotne sieci domyślnej w ten sposób:

Kotlin

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)
    }
})

Java

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);
    }
});

Gdy nowa sieć stanie się domyślną, aplikacja otrzyma wywołanie onAvailable(Network) dla nowej sieci. Wdrożyć onCapabilitiesChanged(Network,NetworkCapabilities), onLinkPropertiesChanged(Network,LinkProperties) lub oba te rozwiązania, aby odpowiednio reagować na zmiany w połączeniu.

W przypadku wywołania zwrotnego zarejestrowanego w registerDefaultNetworkCallback() wartość onLost() oznacza, że sieć utraciła status sieci domyślnej. Może być odłączony.

Możesz dowiedzieć się, z jakich transportów korzysta sieć domyślna, wysyłając zapytanie NetworkCapabilities.hasTransport(int), ale nie jest to dobry sposób na określenie przepustowości ani pomiaru natężenia ruchu w sieci. Aplikacja nie może zakładać, że Wi-Fi jest zawsze nielimitowane i zawsze zapewnia większą przepustowość niż sieć komórkowa.

Zamiast tego użyj NetworkCapabilities.getLinkDownstreamBandwidthKbps() do pomiaru przepustowości, a NetworkCapabilites.hasCapability(int) z argumentami NET_CAPABILITY_NOT_METERED do określenia pomiaru wykorzystania. Więcej informacji znajdziesz w sekcji NetworkCapabilities i LinkProperties.

Domyślnie metody wywołania są wywoływane w wątku łączności aplikacji, który jest oddzielnym wątkiem używanym przez ConnectivityManager. Jeśli implementacja funkcji wywołujących ma wykonać dłuższą pracę, wywołaj je na osobnym wątku roboczym, używając wariantu ConnectivityManager.registerDefaultNetworkCallback(NetworkCallback, Handler).

Jeśli nie chcesz już korzystać z tej funkcji, możesz ją anulować, dzwoniąc pod numer ConnectivityManager.unregisterNetworkCallback(NetworkCallback). W tym celu możesz użyć onPause() w Twojej głównej aktywności, zwłaszcza jeśli rejestrujesz połączenie zwrotne w onResume().

Sieci dodatkowe

Chociaż domyślna sieć jest jedyną odpowiednią siecią dla większości aplikacji, niektóre aplikacje mogą być zainteresowane innymi dostępnymi sieciami. Aby się o tym dowiedzieć, aplikacje tworzą NetworkRequest pasujące do ich potrzeb i wywołują ConnectivityManager.registerNetworkCallback(NetworkRequest, NetworkCallback).

Ten proces przypomina nasłuchiwanie sieci domyślnej. Mimo że w danym momencie może istnieć tylko jedna sieć domyślna, która dotyczy aplikacji, ta wersja pozwala aplikacji zobaczyć wszystkie dostępne sieci jednocześnie. wywołanie onLost(Network) oznacza więc, że sieć została odłączona na stałe, ale nie jest już ustawiona jako domyślna.

Aplikacja tworzy NetworkRequest, aby poinformować ConnectivityManager, jakie sieci chce nasłuchiwać. Ten przykład pokazuje, jak utworzyć NetworkRequest dla aplikacji, która interesuje się tylko nielimitowanymi połączeniami z internetem:

Kotlin

val request = NetworkRequest.Builder()
  .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED)
  .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
  .build()

connectivityManager.registerNetworkCallback(request, myNetworkCallback)

Java

NetworkRequest request = new NetworkRequest.Builder()
  .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED)
  .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
  .build();

connectivityManager.registerNetworkCallback(request, myNetworkCallback);

Oznacza to, że Twoja aplikacja jest informowana o wszystkich zmianach dotyczących nielimitowanych sieci w systemie.

Jeśli chodzi o domyślne wywołanie zwrotne sieci, istnieje wersja registerNetworkCallback(NetworkRequest, NetworkCallback, Handler), która akceptuje Handler, więc nie wczytuje wątku Connectivity Twojej aplikacji.

Zadzwoń pod numerConnectivityManager.unregisterNetworkCallback(NetworkCallback), gdy oddzwanianie nie jest już potrzebne. Aplikacja może jednocześnie rejestrować wiele wywołań zwrotnych sieci.

Dla wygody obiekt NetworkRequest zawiera typowe funkcje, których wymaga większość aplikacji, w tym:

Podczas pisania aplikacji sprawdź domyślne wartości, aby sprawdzić, czy pasują do Twojego przypadku użycia. Usuń je, jeśli chcesz, aby aplikacja była powiadamiana o sieciach, które nie mają tych funkcji. Z drugiej strony dodaj funkcje, aby uniknąć wywoływania w przypadku zmian w łączności w sieciach, z którymi aplikacja nie wchodzi w interakcję.

Jeśli np. Twoja aplikacja musi wysyłać wiadomości MMS, dodaj NET_CAPABILITY_MMS do NetworkRequest, aby uniknąć wyświetlania powiadomień o tym, że nie można wysyłać wiadomości MMS w przypadku wszystkich sieci. Dodaj TRANSPORT_WIFI_AWARE, jeśli Twoja aplikacja obsługuje tylko połączenia P2P przez Wi-Fi. NET_CAPABILITY_INTERNETNET_CAPABILITY_VALIDATED są przydatne, jeśli chcesz przesyłać dane na serwer w internecie.

Przykładowa sekwencja wywołania zwrotnego

W tej sekcji opisaliśmy sekwencję wywołań zwrotnych, które może otrzymać aplikacja, jeśli zarejestruje zarówno wywołanie zwrotne domyślne, jak i zwykłe wywołanie zwrotne na urządzeniu z dostępem do sieci komórkowej. W tym przykładzie urządzenie łączy się z dobrym punktem dostępu Wi-Fi, a następnie się z nim rozłącza. W tym przykładzie zakładamy też, że na urządzeniu włączone jest ustawienie Mobilna transmisja danych zawsze aktywna.

Harmonogram wygląda tak:

  1. Gdy aplikacja wywołuje funkcję registerNetworkCallback(), funkcja wywołania zwrotnego natychmiast otrzymuje połączenia z onAvailable(), onNetworkCapabilitiesChanged()onLinkPropertiesChanged() w sieci komórkowej, ponieważ tylko ta sieć jest dostępna. Jeśli jest dostępna inna sieć, aplikacja otrzymuje też wywołania zwrotne dla tej sieci.

    Diagram stanu przedstawiający zarejestrowanie zdarzenia wywołania zwrotnego sieci i wywołań zwrotnych wywołane przez to zdarzenie
    Rysunek 1. Stan aplikacji po wywołaniu funkcji registerNetworkCallback().

  2. Następnie aplikacja wywołuje metodę registerDefaultNetworkCallback(). Domyślny wywoływany adres sieci zaczyna odbierać połączenia na adresy onAvailable(), onNetworkCapabilitiesChanged() i onLinkPropertiesChanged() w sieci komórkowej, ponieważ jest to sieć domyślna. Jeśli jest aktywna inna sieć inna niż domyślna, aplikacja nie może odbierać połączeń na sieć inną niż domyślna.

    Diagram stanu pokazujący rejestrowanie domyślnego zdarzenia wywołania zwrotnego sieci i wywołania zwrotne wywołane przez to zdarzenie
    Rysunek 2. Stan aplikacji po zarejestrowaniu sieci domyślnej.

  3. Później urządzenie łączy się z siecią Wi-Fi (bez limitu). Zwykły wywołanie zwrotne sieci otrzymuje połączenia na numery onAvailable(), onNetworkCapabilitiesChanged() i onLinkPropertiesChanged() w sieci Wi-Fi.

    Diagram stanu pokazujący wywołania zwrotne wywoływane po połączeniu aplikacji z nową siecią
    Rysunek 3. Stan aplikacji po połączeniu z nielimitowaną siecią Wi-Fi.

  4. W tym momencie może być konieczne sprawdzenie sieci Wi-Fi. W tym przypadku wywołania onNetworkCapabilitiesChanged() w ramach zwykłego wywołania zwrotnego sieci nie obejmują funkcji NET_CAPABILITY_VALIDATED. Po chwili otrzymuje ono wywołanie do onNetworkCapabilitiesChanged(), gdzie nowe możliwości obejmują NET_CAPABILITY_VALIDATED. W większości przypadków weryfikacja trwa bardzo krótko.

    Gdy sieć Wi-Fi jest prawidłowa, system preferuje ją od sieci komórkowej, głównie dlatego, że nie jest to sieć płatna. Sieć Wi-Fi staje się siecią domyślną, więc wywołanie zwrotne sieci domyślnej otrzymuje wywołanie do onAvailable(), onNetworkCapabilitiesChanged() i onLinkPropertiesChanged() dla sieci Wi-Fi. Sieć komórkowa przechodzi w tło, a zwykła sieć wywołuje sieć komórkową.onLosing()

    W tym przykładzie zakładamy, że na tym urządzeniu dane mobilne są zawsze włączone, więc sieć komórkowa nigdy się nie rozłącza. Jeśli to ustawienie jest wyłączone, po pewnym czasie sieć komórkowa zostanie rozłączona i zwykłe wywołanie zwrotne sieci otrzyma wywołanie onLost().

    Diagram stanów przedstawiający wywołania zwrotne wywoływane po potwierdzeniu połączenia z siecią Wi-Fi
    Rysunek 4. Stan aplikacji po zweryfikowaniu sieci Wi-Fi.

  5. Po jakimś czasie urządzenie nagle rozłącza się z Wi-Fi, ponieważ jest poza zasięgiem. Ponieważ połączenie Wi-Fi zostało utracone, regularny wywołanie zwrotne sieci otrzymuje połączenie z numeru onLost() dla Wi-Fi. Ponieważ sieć komórkowa jest nową siecią domyślną, wywołanie zwrotne sieci domyślnej odbiera połączenia na numery onAvailable(), onNetworkCapabilitiesChanged() i onLinkPropertiesChanged() w sieci komórkowej.

    Diagram stanów przedstawiający wywołania zwrotne wywoływane po utracie połączenia z siecią Wi-Fi
    Rysunek 5. Stan aplikacji po rozłączeniu z siecią Wi-Fi.

Jeśli ustawienie Mobilna transmisja danych jest zawsze włączone, po rozłączeniu Wi-Fi urządzenie spróbuje ponownie połączyć się z siecią komórkową. Obraz jest podobny, ale w przypadku połączeń onAvailable() występuje krótki dodatkowy opóźnienie. Z sieci regularnych połączeń zwrotnych dochodzą też połączenia na numery onAvailable(), onNetworkCapabilitiesChanged()onLinkPropertiesChanged(), ponieważ staje się dostępny mobilny numer telefonu.

ograniczenia dotyczące korzystania z sieci na potrzeby przesyłania danych;

Możliwość wyświetlenia sieci za pomocą funkcji wywołania zwrotnego sieci nie oznacza, że aplikacja może używać tej sieci do przesyłania danych. Niektóre sieci nie zapewniają łączności z internetem, a inne mogą być dostępne tylko dla wybranych aplikacji. Aby sprawdzić połączenie z internetem, zapoznaj się z instrukcjami NET_CAPABILITY_INTERNET i NET_CAPABILITY_VALIDATED.

Korzystanie z sieci w tle również podlega kontroli uprawnień. Jeśli Twoja aplikacja chce korzystać z sieci w tle, musi mieć uprawnienie CHANGE_NETWORK_STATE.

Aplikacje z tymi uprawnieniami umożliwiają systemowi próbę włączenia sieci, która jest wyłączona, np. sieci komórkowej, gdy urządzenie jest połączone z siecią Wi-Fi. Taka aplikacja wywołuje ConnectivityManager.requestNetwork(NetworkRequest, NetworkCallback)z parametrem NetworkCallback, który ma być wywoływany po uruchomieniu sieci.