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. Gdy sieć zostanie rozłączona, obiekt Network przestaje być dostępny. Nawet jeśli urządzenie później ponownie połączy się z tym samym urządzeniem, nowy obiekt Network będzie reprezentować 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. Te metody są przydatne do debugowania i okresowego sprawdzania stanu połączenia w danym momencie.

Jednak metody synchroniczne ConnectivityManager nie informują aplikacji o niczym, co dzieje się po wywołaniu, więc nie pozwalają na aktualizowanie 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ń. 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 uzyskać dostęp do dodatkowych funkcji, zarejestruj konto NetworkCallback. Więcej informacji o rejestrowaniu wywołań zwrotnych sieci znajdziesz w artykule Odbieranie 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 fizycznego medium, w którym 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 jest sieć VPN działająca w sieci Wi-Fi i komórkowej. 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_*.

Najprzydatniejsze 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. Sieć może na przykład umożliwiać dostęp do internetu, ale wymagać korzystania z portalu przechwytującego.

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

  • NET_CAPABILITY_NOT_METERED: wskazuje, że sieć nie jest objęta pomiarem użycia danych. Sieć jest klasyfikowana jako taryfowa, gdy użytkownik jest wrażliwy na duże zużycie danych w ramach tego połączenia z powodu kosztów finansowych, ograniczeń 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 utracie łączności z powodu problemów takich jak słaby sygnał.

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

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

Funkcje sieci mogą się zmieniać w każdej chwili. Gdy system wykryje portal, wyświetla powiadomienie zapraszające użytkownika do zalogowania się. Podczas trwania 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.

Podobnie transporty sieci mogą się zmieniać dynamicznie. 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 dowiedzieć się więcej o zdarzeniach sieciowych, użyj klasy NetworkCallback 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 domyślna może się zmienić w dowolnym momencie podczas istnienia aplikacji. Typowym przykładem jest urządzenie, które znajdzie się w zasięgu znanej, aktywnej, nielimitowanej i szybszej niż mobilna sieci Wi-Fi. Urządzenie łączy się z tym punktem dostępu i przełącza sieć domyślną dla wszystkich aplikacji na nową sieć Wi-Fi.

Gdy nowa sieć stanie się domyślną, każde nowe połączenie otwierane przez aplikację będzie korzystać z 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ę domyślna sieć, rejestruje wywołanie zwrotne domyślnej sieci 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żenie onCapabilitiesChanged(Network,NetworkCapabilities), onLinkPropertiesChanged(Network,LinkProperties)lub obu tych rozwiązań, aby odpowiednio reagować na zmiany w połączeniach.

W przypadku wywołania zwrotnego zarejestrowanego w registerDefaultNetworkCallback() wartość onLost() oznacza, że sieć utraciła status sieci domyślnej. Może być rozłą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 argumentu NetworkCapabilities.getLinkDownstreamBandwidthKbps() do pomiaru przepustowości i NetworkCapabilites.hasCapability(int) do określenia pomiaru.NET_CAPABILITY_NOT_METERED 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 uzyskać więcej informacji na ich temat, aplikacje tworzą NetworkRequest dopasowane do swoich potrzeb i wywołują ConnectivityManager.registerNetworkCallback(NetworkRequest, NetworkCallback).

Proces jest podobny do nasłuchiwania w sieci domyślnej. Chociaż w danym momencie może być tylko jedna sieć domyślna, która ma zastosowanie do aplikacji, ta wersja pozwala aplikacji widzieć wszystkie dostępne sieci jednocześnie. Dlatego wywołanie funkcji onLost(Network) oznacza, że sieć została trwale odłączona, a nie że nie jest już domyślną.

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.

W przypadku domyślnego wywołania zwrotnego sieci istnieje wersja registerNetworkCallback(NetworkRequest, NetworkCallback, Handler), która akceptuje Handler, więc nie wczytuje wątku Connectivity w 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 zmiany łą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 wywołanie zwrotne rejestracji sieci i wywołania zwrotne wywołane przez to zdarzenie
    Rysunek 1. Stan aplikacji po wywołaniu funkcji registerNetworkCallback().

  2. Następnie aplikacja wywołuje funkcję 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 wywołanie zwrotne domyślnego zdarzenia 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 odbiera 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 wywołanie do onNetworkCapabilitiesChanged(), gdzie nowe możliwości obejmują NET_CAPABILITY_VALIDATED. W większości przypadków weryfikacja przebiega bardzo szybko.

    Gdy sieć Wi-Fi jest prawidłowa, system preferuje ją od sieci komórkowej, głównie dlatego, że nie jest to sieć taryfowana. 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 do tła, 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 chwili sieć komórkowa się rozłączy, a zwykły wywołujący z sieci otrzyma połączenie na numer onLost().

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

  5. Później urządzenie nagle rozłącza się z Wi-Fi, ponieważ znajduje się poza zasięgiem. Ponieważ połączenie Wi-Fi zostało utracone, regularny wywołujący sieci otrzymuje wywołanie do onLost() dla Wi-Fi. Ponieważ sieć komórkowa jest nową siecią domyślną, wywołanie zwrotne sieci domyślnej odbiera połączenia do 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 zawsze włączona jest wyłączone, gdy połączenie Wi-Fi zostanie utracone, urządzenie spróbuje ponownie połączyć się z siecią komórkową. Obraz jest podobny, ale w przypadku połączeń onAvailable() występuje krótka dodatkowa zwłoka. Zwykle połączenia z powrotem z sieci są też dostępne w przypadku numerów onAvailable(), onNetworkCapabilitiesChanged()onLinkPropertiesChanged(), ponieważ staje się dostępny mobilny numer.

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 korzystać z 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 artykułem NET_CAPABILITY_INTERNETNET_CAPABILITY_VALIDATED.

Używanie sieci w tle również podlega weryfikacji uprawnień. Jeśli 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 nie jest włą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.