Android consente alle app di apprendere i cambiamenti dinamici della connettività. Utilizza le seguenti classi per monitorare e rispondere ai cambiamenti di connettività:
ConnectivityManager
comunica alla tua app lo stato della connettività nel sistema.- La classe
Network
rappresenta una delle reti a cui è connesso il dispositivo. Puoi utilizzare l'oggettoNetwork
come chiave per raccogliere informazioni sulla rete conConnectivityManager
o per associare i socket sulla rete. Quando la rete si disconnette, l'oggettoNetwork
smette di essere utilizzabile. Anche se in un secondo momento il dispositivo si riconnette alla stessa appliance, un nuovo oggettoNetwork
rappresenta la nuova rete. - L'oggetto
LinkProperties
contiene informazioni sul collegamento di una rete, come l'elenco di server DNS, gli indirizzi IP locali e le route di rete installate per la rete. - L'oggetto
NetworkCapabilities
contiene informazioni sulle proprietà di una rete, come i trasporti (Wi-Fi, dispositivi mobili, Bluetooth) e le capacità della rete. Ad esempio, puoi eseguire una query sull'oggetto per determinare se la rete è in grado di inviare MMS, è dietro un captive portal o è a consumo.
Le app interessate allo stato immediato della connettività in un dato momento possono chiamare metodi ConnectivityManager
per scoprire quale tipo di rete è disponibile. Questi metodi sono utili per il debug e per esaminare occasionalmente uno snapshot della connettività disponibile in un determinato momento.
Tuttavia, i metodi ConnectivityManager
sincroni non comunicano all'app nulla di ciò che accade dopo una chiamata, quindi non ti consentono di aggiornare la UI. Inoltre, non possono regolare il comportamento delle app in base alla disconnessione della rete o a quando cambiano le funzionalità di rete.
La connettività può cambiare in qualsiasi momento e la maggior parte delle app deve avere una visione sempre aggiornata e aggiornata dello stato del networking sul dispositivo. Le app possono
registrare un callback con ConnectivityManager
per ricevere avvisi sulle modifiche importanti
per l'app. Utilizzando il callback, l'app può reagire immediatamente a qualsiasi
modifica pertinente nella connettività, senza dover ricorrere a sondaggi costosi
che potrebbero perdere aggiornamenti rapidi.
L'utilizzo di NetworkCallback
e altri modi per scoprire lo stato della connettività del dispositivo non richiede alcuna autorizzazione particolare.
Tuttavia, alcune reti sono soggette a autorizzazioni specifiche.
Ad esempio, potrebbero non essere disponibili reti con limitazioni per le app. L'associazione a una
rete in background richiede l'autorizzazione CHANGE_NETWORK_STATE
. Inoltre, alcune chiamate potrebbero richiedere autorizzazioni specifiche per l'esecuzione. Per informazioni dettagliate, consulta la documentazione specifica di ciascuna chiamata.
Ottieni stato istantaneo
Un dispositivo Android è in grado di mantenere molte connessioni contemporaneamente.
Per informazioni sullo stato attuale della rete, ottieni prima
un'istanza di ConnectivityManager
:
Kotlin
val connectivityManager = getSystemService(ConnectivityManager::class.java)
Java
ConnectivityManager connectivityManager = getSystemService(ConnectivityManager.class);
Quindi, utilizza questa istanza per ottenere un riferimento alla rete predefinita attuale per la tua app:
Kotlin
val currentNetwork = connectivityManager.getActiveNetwork()
Java
Network currentNetwork = connectivityManager.getActiveNetwork();
Quando fai riferimento a una rete, l'app può richiedere informazioni in merito:
Kotlin
val caps = connectivityManager.getNetworkCapabilities(currentNetwork) val linkProperties = connectivityManager.getLinkProperties(currentNetwork)
Java
NetworkCapabilities caps = connectivityManager.getNetworkCapabilities(currentNetwork); LinkProperties linkProperties = connectivityManager.getLinkProperties(currentNetwork);
Per funzionalità più utili, registra una NetworkCallback
.
Per maggiori informazioni sulla registrazione dei callback di rete, consulta
Ascoltare gli eventi di rete.
NetworkCapabilities e LinkProperties
Gli oggetti NetworkCapabilities
e LinkProperties
forniscono informazioni su tutti gli attributi di una rete noti al sistema.
L'oggetto LinkProperties
conosce route, indirizzi di collegamento, nome interfaccia, informazioni proxy (se presenti) e server DNS. Chiama il metodo pertinente sull'oggetto LinkProperties
per recuperare le informazioni necessarie.
L'oggetto NetworkCapabilities
incapsula le informazioni sui trasporti della rete e sulle relative funzionalità.
Un trasporto è un'astrazione di un supporto fisico su cui opera una rete. Esempi comuni di trasporti sono Ethernet, Wi-Fi e dispositivi mobili.
Anche le VPN e il Wi-Fi peer-to-peer possono essere mezzi di trasporto.
Su Android, una rete può supportare più trasporti contemporaneamente. Un esempio è una VPN che opera sia su reti Wi-Fi che su reti mobili. La VPN include i trasporti
Wi-Fi, mobile e VPN. Per scoprire se una
rete ha un determinato trasporto, utilizza il metodo
NetworkCapabilities.hasTransport(int)
con una delle costanti NetworkCapabilities.TRANSPORT_*
.
Una funzionalità descrive una proprietà della rete. Esempi di funzionalità includono
MMS
, NOT_METERED
e INTERNET
. Una rete con funzionalità MMS può inviare e ricevere messaggi da Multimedia Messaging Service, mentre una rete senza questa funzionalità non può farlo. Una rete con funzionalità NOT_METERED
non addebita
i dati all'utente. La tua app può verificare le funzionalità appropriate utilizzando il metodo
NetworkCapabilities.hasCapability(int)
con una delle costanti NetworkCapabilities.NET_CAPABILITY_*
.
Le costanti NET_CAPABILITY_*
più utili includono:
NET_CAPABILITY_INTERNET
: indica che la rete è configurata per accedere a internet. Riguarda la configurazione, non la reale possibilità di raggiungere i server pubblici. Ad esempio, una rete può essere configurata per accedere a internet, ma essere soggetta a un captive portal.In genere la rete mobile di un operatore offre la funzionalità
INTERNET
, al contrario di una rete Wi-Fi P2P locale. Per la connettività effettiva, consultaNET_CAPABILITY_VALIDATED
.NET_CAPABILITY_NOT_METERED
: indica che la rete non è a consumo. Una rete viene classificata come a consumo quando l'utente è sensibile a un utilizzo intensivo dei dati su quella connessione a causa di costi monetari, limitazioni dei dati o problemi di prestazioni della batteria.NET_CAPABILITY_NOT_VPN
: indica che la rete non è una rete privata virtuale.NET_CAPABILITY_VALIDATED
: indica che la rete fornisce l'accesso effettivo alla rete internet pubblica quando viene controllata. Una rete dietro un captive portal o una rete che non fornisce la risoluzione dei nomi di dominio non dispone di questa funzionalità. Si tratta dell'informazione più vicina che il sistema può rilevare riguardo a una rete che fornisce effettivamente l'accesso, sebbene una rete convalidata possa comunque essere soggetta a filtri basati su IP o subire improvvise perdite di connettività a causa di problemi quali un segnale debole.NET_CAPABILITY_CAPTIVE_PORTAL
: indica che la rete ha un captive portal quando viene sottoposto a sonda.
Esistono altre funzionalità che potrebbero essere interessate alle app più specializzate.
Per ulteriori informazioni, leggi le definizioni dei parametri in
NetworkCapabilities.hasCapability(int)
.
Le funzionalità di una rete possono cambiare in qualsiasi momento. Quando il sistema rileva un captive portal, mostra una notifica che invita l'utente ad accedere. Finché questa operazione
è in corso, la rete ha le funzionalità NET_CAPABILITY_INTERNET
e
NET_CAPABILITY_CAPTIVE_PORTAL
, ma non la funzionalità
NET_CAPABILITY_VALIDATED
.
Quando l'utente interviene e accede alla pagina del captive portal, il dispositivo diventa in grado di accedere alla rete internet pubblica e la rete acquisisce la funzionalità NET_CAPABILITY_VALIDATED
e perde la funzionalità NET_CAPABILITY_CAPTIVE_PORTAL
.
Analogamente, i trasporti di una rete possono cambiare in modo dinamico.
Ad esempio, una VPN può riconfigurarsi per usare una rete più veloce appena creata, come il passaggio da una rete mobile al Wi-Fi per la rete sottostante. In questo caso, la rete perde il trasporto TRANSPORT_CELLULAR
e ottiene il trasporto TRANSPORT_WIFI
, mantenendo il
trasporto TRANSPORT_VPN
.
Ascoltare eventi di rete
Per saperne di più sugli eventi di rete, utilizza la classe NetworkCallback
insieme a ConnectivityManager.registerDefaultNetworkCallback(NetworkCallback)
e ConnectivityManager.registerNetworkCallback(NetworkCallback)
. Questi due metodi hanno scopi
diversi.
Tutte le app per Android hanno una rete predefinita, determinata dal sistema. In genere il sistema preferisce le reti unmetered a quelle a consumo e le reti più veloci a quelle più lente.
Quando un'app invia una richiesta di rete, ad esempio con HttpsURLConnection
, il sistema soddisfa questa richiesta utilizzando la rete predefinita. Le app possono inviare traffico
anche su altre reti. Per ulteriori informazioni, consulta la sezione relativa alle reti aggiuntive.
La rete impostata come rete predefinita può cambiare in qualsiasi momento durante il ciclo di vita di un'app. Un esempio tipico è il dispositivo che entra nella portata di un punto di accesso Wi-Fi noto, attivo, non a consumo e più veloce di un dispositivo mobile. Il dispositivo si connette a questo punto di accesso e commuta la rete predefinita per tutte le app alla nuova rete Wi-Fi.
Quando una nuova rete diventa predefinita, ogni nuova connessione aperta dall'app utilizza questa rete. In seguito, tutte le connessioni rimanenti sulla rete predefinita precedente vengono terminate in modo forzato. Se è importante che l'app sappia quando cambia la rete predefinita, l'app registra un callback di rete predefinito come segue:
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); } });
Quando una nuova rete diventa predefinita, l'app riceve una chiamata a onAvailable(Network)
per la nuova rete. Implementa
onCapabilitiesChanged(Network,NetworkCapabilities)
,
onLinkPropertiesChanged(Network,LinkProperties)
o entrambi per reagire in modo appropriato ai cambiamenti nella connettività.
Per un callback registrato con registerDefaultNetworkCallback()
, onLost()
significa che la rete non è più la rete predefinita. Potrebbe essere disconnesso.
Anche se puoi scoprire i trasporti utilizzati dalla rete predefinita eseguendo query su
NetworkCapabilities.hasTransport(int)
,
questo è un proxy scadente per la larghezza di banda o la misurazione della rete. La tua app
non può presumere che la rete Wi-Fi sia sempre illimitata e fornisce sempre una larghezza di banda migliore
rispetto a quella mobile.
Utilizza invece
NetworkCapabilities.getLinkDownstreamBandwidthKbps()
per misurare la larghezza di banda e
NetworkCapabilites.hasCapability(int)
con argomenti
NET_CAPABILITY_NOT_METERED
per determinare la misurazione. Per ulteriori informazioni, consulta la sezione su
NetworkCapabilities e LinkProperties.
Per impostazione predefinita, i metodi di callback vengono chiamati nel thread di connettività
della tua app, che è un thread separato utilizzato da ConnectivityManager
. Se la tua implementazione dei callback deve funzionare più, richiamali in un thread worker separato utilizzando la variante ConnectivityManager.registerDefaultNetworkCallback(NetworkCallback, Handler)
.
Annulla la registrazione del callback quando non lo utilizzi più chiamando il numero
ConnectivityManager.unregisterNetworkCallback(NetworkCallback)
.
L'elemento onPause()
dell'attività principale
è un buon posto per farlo, soprattutto se registri il callback in
onResume()
.
Altre reti
Sebbene la rete predefinita sia l'unica pertinente per la maggior parte delle app, alcune
potrebbero essere interessate ad altre reti disponibili. Per scoprirli, le app
creano una NetworkRequest
adatta alle loro
esigenze e chiamano
ConnectivityManager.registerNetworkCallback(NetworkRequest, NetworkCallback)
.
La procedura è simile all'ascolto
di una rete predefinita. Tuttavia, anche se potrebbe esistere una sola rete predefinita in un determinato momento, questa versione consente all'app di vedere tutte le reti disponibili contemporaneamente, quindi una chiamata a onLost(Network)
indica che la rete si è disconnessa definitivamente, dato che non è più quella predefinita.
L'app crea un NetworkRequest
per comunicare a ConnectivityManager
il tipo
di reti che vuole ascoltare. L'esempio seguente mostra come creare un NetworkRequest
per un'app interessata solo alle connessioni a internet illimitate:
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);
Ciò significa che la tua app viene a conoscenza di tutte le modifiche relative a una rete unmetered sul sistema.
Per quanto riguarda il callback di rete predefinito, esiste una versione di registerNetworkCallback(NetworkRequest, NetworkCallback, Handler)
che accetta Handler
in modo che non carichi il thread Connectivity
della tua app.
Chiama il numero ConnectivityManager.unregisterNetworkCallback(NetworkCallback)
se il callback non è più pertinente. Un'app può registrare contemporaneamente
più callback di rete.
Per praticità, l'oggetto NetworkRequest
contiene le funzionalità comuni necessarie alla maggior parte delle app, tra cui:
Quando scrivi l'app, controlla i valori predefiniti per vedere se corrispondono al tuo caso d'uso e cancellali se vuoi che l'app riceva notifiche sulle reti che non dispongono di queste funzionalità. D'altra parte, aggiungi funzionalità per evitare di ricevere chiamate per qualsiasi modifica di connettività nelle reti con cui la tua app non interagisce.
Ad esempio, se la tua app deve inviare messaggi MMS, aggiungi NET_CAPABILITY_MMS
a NetworkRequest
per evitare di ricevere informazioni su tutte le reti che non possono inviare messaggi MMS. Aggiungi
TRANSPORT_WIFI_AWARE
se alla tua app interessa soltanto la connettività Wi-Fi P2P.
NET_CAPABILITY_INTERNET
e
NET_CAPABILITY_VALIDATED
sono utili se vuoi avere la possibilità di trasferire i dati con un server su internet.
Esempio di sequenza di callback
Questa sezione descrive la sequenza di callback che un'app potrebbe ricevere se registra sia un callback predefinito sia un callback normale su un dispositivo che dispone di connettività mobile. In questo esempio, il dispositivo si connette a un buon punto di accesso Wi-Fi, quindi si disconnette. L'esempio presuppone anche che sul dispositivo sia attivata l'impostazione Dati mobili sempre attivi.
Le tempistiche sono le seguenti:
Quando l'app chiama il numero
registerNetworkCallback()
, il callback riceve immediatamente le chiamate daonAvailable()
,onNetworkCapabilitiesChanged()
eonLinkPropertiesChanged()
per la rete mobile, perché è disponibile solo questa rete. Se è disponibile un'altra rete, l'app riceve anche i callback per l'altra rete.
Figura 1. Stato dell'app dopo la chiamata aregisterNetworkCallback()
.Poi l'app chiama
registerDefaultNetworkCallback()
. Il callback di rete predefinito inizia a ricevere chiamate aonAvailable()
,onNetworkCapabilitiesChanged()
eonLinkPropertiesChanged()
per la rete mobile, perché la rete mobile è la rete predefinita. Se è attiva un'altra rete non predefinita, l'app non può ricevere chiamate per la rete non predefinita.
Figura 2. Stato dell'app dopo la registrazione di una rete predefinita.In seguito, il dispositivo si connetterà a una rete Wi-Fi (non a consumo). Il normale callback di rete riceve chiamate a
onAvailable()
,onNetworkCapabilitiesChanged()
eonLinkPropertiesChanged()
per la rete Wi-Fi.
Figura 3. Stato dell'app dopo la connessione a una rete Wi-Fi senza limiti.A questo punto, la convalida della rete Wi-Fi potrebbe richiedere un po' di tempo. In questo caso, le chiamate
onNetworkCapabilitiesChanged()
per il callback di rete normale non includono la funzionalitàNET_CAPABILITY_VALIDATED
. Dopo un breve lasso di tempo, riceve una chiamata aonNetworkCapabilitiesChanged()
, dove le nuove funzionalità includonoNET_CAPABILITY_VALIDATED
. Nella maggior parte dei casi, la convalida è molto rapida.Dopo la convalida della rete Wi-Fi, il sistema la preferisce alla rete mobile, principalmente perché non è a consumo. La rete Wi-Fi diventa la rete predefinita, quindi il callback di rete predefinito riceve una chiamata a
onAvailable()
,onNetworkCapabilitiesChanged()
eonLinkPropertiesChanged()
per la rete Wi-Fi. La rete mobile va in background e il normale callback di rete riceve una chiamata al numeroonLosing()
per la rete mobile.Poiché in questo esempio si presume che i dati mobili siano sempre attivi per il dispositivo, la rete mobile non si disconnette mai. Se l'impostazione è disattivata, dopo un po' la rete mobile si disconnette e il normale callback di rete riceve una chiamata al numero
onLost()
.
Figura 4. Stato dell'app dopo la convalida della rete Wi-Fi.In seguito, il dispositivo si è comunque disconnesso improvvisamente dalla rete Wi-Fi perché è uscito dal raggio d'azione. Poiché la rete Wi-Fi viene scollegata, il normale callback di rete riceve una chiamata al numero
onLost()
per il Wi-Fi. Poiché la rete mobile è la nuova rete predefinita, il callback di rete predefinito riceve le chiamate aonAvailable()
,onNetworkCapabilitiesChanged()
eonLinkPropertiesChanged()
per la rete mobile.
Figura 5. Stato dell'app dopo la disconnessione dalla rete Wi-Fi.
Se l'impostazione Dati mobili sempre attivi è disattivata, quando il Wi-Fi disconnette il dispositivo prova a riconnettersi a una rete mobile. L'immagine è
simile, ma con un breve ritardo in più per le chiamate onAvailable()
e
il normale callback di rete riceve anche chiamate a onAvailable()
,
onNetworkCapabilitiesChanged()
e onLinkPropertiesChanged()
perché
la rete mobile diventa disponibile.
Restrizioni relative all'uso della rete per il trasferimento di dati
La possibilità di vedere una rete con un callback di rete non significa che l'app può
utilizzare la rete per il trasferimento di dati. Alcune reti non offrono connettività
a internet, mentre altre potrebbero essere limitate ad
app con privilegi. Per verificare la connettività a internet, consulta
NET_CAPABILITY_INTERNET
e
NET_CAPABILITY_VALIDATED
.
Anche l'utilizzo di reti in background è soggetto a controlli delle autorizzazioni. Se la tua app vuole utilizzare una rete in background, ha bisogno dell'autorizzazione CHANGE_NETWORK_STATE
.
Le app con questa autorizzazione consentono al sistema di tentare di visualizzare una rete non attiva, ad esempio la rete mobile, quando il dispositivo è connesso a una rete Wi-Fi. L'app chiama
ConnectivityManager.requestNetwork(NetworkRequest, NetworkCallback)
con NetworkCallback
per essere chiamata quando viene visualizzata la rete.