Odczytywanie stanu sieci

Android umożliwia aplikacjom zapamiętywanie informacji o dynamicznych zmianach w łączności. Użyj poniższych klas, aby śledzić zmiany połączeń i reagować na nie:

  • ConnectivityManager informuje aplikację o stanie połączenia w systemie.
  • Klasa Network reprezentuje jedną z sieci, z którą połączone jest urządzenie. Obiektu Network możesz użyć jako klucza do zbierania informacji o sieci za pomocą 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 z siecią, takie jak lista serwerów DNS, lokalne adresy IP i trasy sieciowe zainstalowane w sieci.
  • Obiekt NetworkCapabilities zawiera informacje o właściwościach sieci, np. o środkach transportu (Wi-Fi, komórkowe lub Bluetooth) oraz o możliwościach sieci. Możesz na przykład wysłać zapytanie do obiektu, aby sprawdzić, czy sieć może wysyłać MMS-y, czy znajduje się za portalem przechwytującym, czy jest objęta pomiarem.

Aplikacje, które w dowolnym momencie chcą mieć natychmiastowy stan połączenia, mogą wywoływać metody ConnectivityManager, aby dowiedzieć się, jaki rodzaj sieci jest dostępny. Metody te są pomocne przy debugowaniu i od czasu do czasu sprawdzaj podsumowanie połączenia, które jest dostępne 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ż dostosować działania aplikacji na podstawie rozłączenia sieci ani zmian możliwości sieci.

Łączność może się zmienić w każdej chwili, a większość aplikacji musi mieć zawsze aktualny wgląd w stan sieci na urządzeniu. Aplikacje mogą zarejestrować wywołanie zwrotne przy użyciu funkcji ConnectivityManager, aby otrzymywać alerty o zmianach, które są dla nich ważne. Dzięki wywołaniu zwrotnemu aplikacja może natychmiast zareagować na każdą istotną zmianę połączenia bez konieczności uciekania się do kosztownych ankiet, które mogłyby przeoczyć szybkie aktualizacje.

Korzystanie z NetworkCallback i innych sposobów sprawdzania stanu połączenia urządzenia nie wymaga żadnych uprawnień. Niektóre sieci wymagają jednak określonych uprawnień. Mogą na przykład istnieć sieci z ograniczonym dostępem, które nie są dostę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 znajdziesz w dokumentacji konkretnego wywołania.

Uzyskaj natychmiastowy stan

Urządzenie z Androidem może obsługiwać 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, by uzyskać odniesienie do bieżącej domyślnej sieci aplikacji:

Kotlin

val currentNetwork = connectivityManager.getActiveNetwork()

Java

Network currentNetwork = connectivityManager.getActiveNetwork();

Dzięki odniesienia do sieci aplikacja może prosić o informacje na jej temat:

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.

Funkcjonalność sieci i właściwości linku

Obiekty NetworkCapabilities i LinkProperties dostarczają informacji o wszystkich atrybutach sieci, które system wie.

Obiekt LinkProperties zna trasy, adresy linków, nazwę interfejsu, informacje o serwerach proxy (jeśli są dostępne) i serwerach DNS. Wywołaj odpowiednią metodę w obiekcie LinkProperties, aby pobrać potrzebne informacje.

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

Transport to abstrakcja nośnika fizycznego, przez który działa sieć. Typowe przykłady sieci transportu to Ethernet, Wi-Fi i sieć komórkowa. Mogą to być również sieci VPN oraz sieci Wi-Fi typu peer-to-peer. Na Androidzie sieć może mieć wiele transportów jednocześnie. Przykładem może być sieć VPN działająca zarówno przez Wi-Fi, jak i sieci komórkowe. Sieć VPN obejmuje sieć Wi-Fi, mobilną i VPN. Aby dowiedzieć się, czy sieć ma określony środek transportu, użyj metody NetworkCapabilities.hasTransport(int) z jedną ze stałych NetworkCapabilities.TRANSPORT_*.

Możliwość opisuje właściwość sieci. Przykładowe możliwości to MMS, NOT_METERED i INTERNET. Sieć obsługująca MMS-y może wysyłać i odbierać wiadomości przy użyciu usługi przesyłania wiadomości multimedialnych, natomiast sieć bez tej funkcji nie będzie mieć takiej możliwości. Sieć obsługująca funkcję NOT_METERED nie nalicza opłat za przesyłanie danych. Aplikacja może sprawdzić odpowiednie możliwości, używając metody NetworkCapabilities.hasCapability(int) z jedną ze stałych NetworkCapabilities.NET_CAPABILITY_*.

Najbardziej przydatne stałe NET_CAPABILITY_* to:

  • NET_CAPABILITY_INTERNET: wskazuje, że sieć jest skonfigurowana pod kątem dostępu do internetu. Chodzi o konfigurację, a nie o rzeczywistą możliwość dostępu 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 rzeczywistych połączeniach znajdziesz na NET_CAPABILITY_VALIDATED.

  • NET_CAPABILITY_NOT_METERED: wskazuje, że sieć nie ma pomiaru wykorzystania limitu. Sieć jest klasyfikowana jako z pomiarem użycia danych, gdy użytkownik wykazuje tendencję do wysokiego poziomu wykorzystania danych przez to połączenie z powodu kosztów finansowych, ograniczeń w danych lub problemów z wydajnością baterii.

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

  • NET_CAPABILITY_VALIDATED: wskazuje, że sieć zapewnia rzeczywisty dostęp do publicznego internetu, gdy jest sondowana. Tej funkcji nie ma w sieciach portalu przechwytującego ani w sieci, która nie obsługuje rozpoznawania nazw domen. Jest to najbliższa wartość, jaką system może wywnioskować na temat sieci rzeczywiście zapewniającej dostęp, chociaż zweryfikowana sieć może w zasadzie podlegać filtrowaniu na podstawie adresu IP lub może dochodzić do nagłej utraty połączenia 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 możliwości, którymi mogą być zainteresowane bardziej specjalistyczne aplikacje. Więcej informacji znajdziesz w definicjach parametrów w artykule NetworkCapabilities.hasCapability(int).

Możliwości sieci mogą się zmienić w każdej chwili. Gdy system wykryje portal przechwytujący, wyświetli powiadomienie z prośbą o zalogowanie. W trakcie tego działania sieć ma możliwości NET_CAPABILITY_INTERNET i NET_CAPABILITY_CAPTIVE_PORTAL, ale nie 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 obsługę NET_CAPABILITY_VALIDATED i utraci możliwość NET_CAPABILITY_CAPTIVE_PORTAL.

Transport w sieci również może się dynamicznie zmieniać. Na przykład sieć VPN może się zmienić w taki sposób, aby korzystała z szybszej sieci, która właśnie powstała. Może na przykład przełączyć się z mobilnej na Wi-Fi w swojej sieci podstawowej. W tym przypadku sieć traci transport publiczny TRANSPORT_CELLULAR i zyskuje transport TRANSPORT_WIFI, zachowując jednocześnie transport TRANSPORT_VPN.

Nasłuchuj zdarzeń sieciowych

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

Wszystkie aplikacje na Androida mają sieć domyślną, która jest określana przez system. System zazwyczaj preferuje sieci bez pomiaru sieci z pomiarem użycia danych, a szybsze sieci od wolniejszych.

Gdy aplikacja wyśle żądanie sieciowe, na przykład za pomocą HttpsURLConnection, system może spełnić to żądanie z użyciem sieci domyślnej. Aplikacje mogą wysyłać ruch również w innych sieciach. Więcej informacji znajdziesz w sekcji o dodatkowych sieciach.

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 domyślnej sieci zostaną wymuszone. Jeśli aplikacja ma wiedzieć o zmianie sieci domyślnej, rejestruje takie wywołanie zwrotne sieci:

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ę siecią domyślną, aplikacja otrzyma w jej przypadku wywołanie onAvailable(Network). Aby odpowiednio reagować na zmiany w łączności, zaimplementuj onCapabilitiesChanged(Network,NetworkCapabilities), onLinkPropertiesChanged(Network,LinkProperties) lub oba te elementy.

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

Chociaż można dowiedzieć się więcej o transmisjach używanych w sieci domyślnej, wysyłając zapytania do NetworkCapabilities.hasTransport(int), nie jest to serwer proxy o słabych parametrach związanych z przepustowością lub pomiarem wykorzystania sieci. Aplikacja nie może zakładać, że sieć Wi-Fi zawsze jest bez pomiaru i ma 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 o funkcjach sieci i właściwościach linków.

Domyślnie metody wywołania zwrotnego są wywoływane w wątku połączenia aplikacji, który jest oddzielnym wątkiem używanym przez funkcję ConnectivityManager. Jeśli implementacja wywołań zwrotnych musi dłużej działać, wywołaj je w osobnym wątku instancji roboczej, używając wariantu ConnectivityManager.registerDefaultNetworkCallback(NetworkCallback, Handler).

Wyrejestruj oddzwonienie, gdy nie jest już używane, pod numerem ConnectivityManager.unregisterNetworkCallback(NetworkCallback). Możesz to zrobić w onPause() głównej aktywności, zwłaszcza jeśli rejestrujesz wywołanie zwrotne w onResume().

Dodatkowe sieci

Mimo że sieć domyślna to jedyna sieć w przypadku 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 obowiązuje w przypadku 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 to już sieć domyślna.

Aplikacja tworzy NetworkRequest, który informuje ConnectivityManager o rodzaju sieci, których chce słuchać. Poniższy przykład pokazuje, jak utworzyć NetworkRequest dla aplikacji zainteresowanej tylko połączeniami z internetem bez pomiaru:

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 aplikacja będzie otrzymywać informacje o wszystkich zmianach dotyczących sieci w systemie bez pomiaru.

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.

Wywołaj ConnectivityManager.unregisterNetworkCallback(NetworkCallback), gdy wywołanie zwrotne nie będzie już aktualne. Aplikacja może jednocześnie rejestrować wiele wywołań zwrotnych sieci.

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

Pisząc aplikację, sprawdź wartości domyślne, aby zobaczyć, czy pasują do Twojego przypadku użycia, i wyczyść je, jeśli chcesz, by aplikacja była powiadamiana o sieciach, które nie mają tych funkcji. Z drugiej strony dodaj funkcje, aby uniknąć wywołania w przypadku zmiany połączenia w sieciach, z którymi Twoja aplikacja nie wchodzi w interakcję.

Jeśli na przykład Twoja aplikacja musi wysyłać MMS-y, dodaj NET_CAPABILITY_MMS do NetworkRequest, aby otrzymywać informacje o wszystkich sieciach, które nie mogą wysyłać MMS-ów. Dodaj TRANSPORT_WIFI_AWARE, jeśli Twoja aplikacja potrzebuje tylko połączeń P2P z siecią Wi-Fi. NET_CAPABILITY_INTERNET i NET_CAPABILITY_VALIDATED są przydatne, jeśli interesuje Cię możliwość przenoszenia danych z serwerem w internecie.

Przykładowa sekwencja wywołania zwrotnego

W tej sekcji opisujemy sekwencję wywołań zwrotnych, które może otrzymać aplikacja, jeśli zarejestruje zarówno domyślne wywołanie zwrotne, jak i zwykłe wywołanie zwrotne na urządzeniu z łącznością komórkową. W tym przykładzie urządzenie łączy się z punktem dostępu Wi-Fi, a potem się od niego rozłącza. W tym przykładzie zakładamy też, że urządzenie ma włączoną opcję Mobilna transmisja danych zawsze włączona.

Harmonogram wygląda tak:

  1. Gdy aplikacja wywoła registerNetworkCallback(), wywołanie zwrotne natychmiast otrzyma połączenia z sieci komórkowej onAvailable(), onNetworkCapabilitiesChanged() i onLinkPropertiesChanged(), ponieważ dostępna jest tylko ta sieć. Jeśli dostępna jest inna sieć, aplikacja odbiera też wywołania zwrotne do 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 aplikacji registerNetworkCallback().

  2. Następnie aplikacja wywołuje metodę registerDefaultNetworkCallback(). Domyślne wywołanie zwrotne sieci zacznie odbierać połączenia z numerami onAvailable(), onNetworkCapabilitiesChanged() i onLinkPropertiesChanged() w przypadku sieci komórkowej, ponieważ domyślną siecią jest sieć komórkowa. Jeśli działa inna sieć inna niż domyślna, aplikacja nie będzie mogła odbierać połączeń z tej sieci.

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

  3. Następnie urządzenie łączy się z siecią Wi-Fi (bez pomiaru). Zwykłe wywołanie zwrotne sieci odbiera połączenia z numerami onAvailable(), onNetworkCapabilitiesChanged() i onLinkPropertiesChanged() w przypadku sieci Wi-Fi.

    Diagram stanu przedstawiający wywołania zwrotne aktywowane, gdy aplikacja łączy się z nową siecią
    Rysunek 3. Stan aplikacji po połączeniu się z siecią Wi-Fi bez pomiaru.

  4. W tym momencie może minąć trochę czasu, zanim sieć Wi-Fi zweryfikuje się. W tym przypadku wywołanie zwrotne onNetworkCapabilitiesChanged() w standardowej sieci nie zawiera funkcji NET_CAPABILITY_VALIDATED. Po krótkim czasie otrzymuje wywołanie onNetworkCapabilitiesChanged(), gdzie do nowych funkcji należą NET_CAPABILITY_VALIDATED. W większości przypadków weryfikacja trwa bardzo krótko.

    Po sprawdzeniu sieci Wi-Fi system preferuje ją od sieci komórkowej, głównie dlatego, że nie jest mierzona. Sieć Wi-Fi staje się siecią domyślną, więc domyślne wywołanie zwrotne sieci Wi-Fi otrzymuje wywołania onAvailable(), onNetworkCapabilitiesChanged() i onLinkPropertiesChanged(). Sieć komórkowa przechodzi w tle, a standardowe wywołanie zwrotne sieci komórkowej otrzymuje wywołanie onLosing().

    W tym przykładzie zakładamy, że mobilna transmisja danych na tym urządzeniu jest zawsze włączona, 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 stanu przedstawiający wywołania zwrotne aktywowane po zweryfikowaniu połączenia sieciowego 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. Wi-Fi się rozłącza, więc zwykłe wywołanie zwrotne sieci przez Wi-Fi otrzyma na adres onLost(). Komórka to nowa sieć domyślna, dlatego domyślne wywołanie zwrotne sieci komórkowej otrzymuje wywołania onAvailable(), onNetworkCapabilitiesChanged() i onLinkPropertiesChanged() dla sieci komórkowej.

    Diagram stanu przedstawiający wywołania zwrotne aktywowane po utracie połączenia z siecią Wi-Fi
    Rysunek 5. Stan aplikacji po odłączeniu od 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 z niewielkim dodatkowym opóźnieniem w przypadku wywołań onAvailable(), a standardowe wywołanie zwrotne sieci otrzymuje też wywołania onAvailable(), onNetworkCapabilitiesChanged() i onLinkPropertiesChanged(), ponieważ dostępne są też urządzenia mobilne.

Ograniczenia dotyczące korzystania z sieci do przesyłania danych

To, że widzisz sieć z wywołaniem zwrotnym, nie oznacza, że aplikacja może używać tej sieci do przesyłania danych. Niektóre sieci nie zapewniają połączenia z internetem, a inne mogą być dostępne tylko dla aplikacji z podwyższonymi uprawnieniami. Aby sprawdzić połączenie z internetem, zapoznaj się z instrukcjami NET_CAPABILITY_INTERNET i NET_CAPABILITY_VALIDATED.

Korzystanie z sieci działających w tle podlega również sprawdzaniu uprawnień. Jeśli Twoja aplikacja chce korzystać z sieci w tle, musi mieć uprawnienie CHANGE_NETWORK_STATE.

Aplikacje z tymi uprawnieniami pozwalają systemowi próbować wyświetlić sieć, która nie działa, np. sieć komórkową, gdy urządzenie jest połączone z siecią Wi-Fi. Taka aplikacja wywołuje ConnectivityManager.requestNetwork(NetworkRequest, NetworkCallback) z elementem NetworkCallback, który zostaje wywołany po wywołaniu sieci.