In Android N wordt op de officiële website vermeld dat “Apps die gericht zijn op Android N geen CONNECTIVITY_ACTION-uitzendingen ontvangen”. En er wordt ook vermeld dat JobScheduler
als alternatief kan worden gebruikt. Maar de JobScheduler
biedt niet precies hetzelfde gedrag als de uitzending van CONNECTIVITY_ACTION
.
In mijn Android-applicatie gebruikte ik deze uitzending om de netwerkstatus van het apparaat te weten. Ik wilde weten of deze status CONNECTING
of CONNECTED
was met behulp van CONNECTIVITY_ACTION
uitzending en het was het meest geschikt voor mijn vereiste.
Nu het verouderd is, kan iemand mij de alternatieve benadering voorstellen om de huidige netwerkstatus te krijgen?
Antwoord 1, autoriteit 100%
Wat zal worden afgeschaft, is de mogelijkheid voor een app op de achtergrond om statuswijzigingen van de netwerkverbinding te ontvangen.
Zoals David Wasserzei dat je nog steeds op de hoogte kunt worden gehouden van connectiviteitswijzigingen als de app-component is geïnstantieerd (niet vernietigd ) en je hebt uw ontvanger programmatisch geregistreerdmet zijn context, in plaats van dit in het manifest te doen.
Of u kunt in plaats daarvan NetworkCallbackgebruiken. In het bijzonder moet u negeren onAvailablevoor wijzigingen in verbonden status.
Laat me snel een fragment opstellen:
public class ConnectionStateMonitor extends NetworkCallback {
final NetworkRequest networkRequest;
public ConnectionStateMonitor() {
networkRequest = new NetworkRequest.Builder()
.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
.build();
}
public void enable(Context context) {
ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
connectivityManager.registerNetworkCallback(networkRequest, this);
}
// Likewise, you can have a disable method that simply calls ConnectivityManager.unregisterNetworkCallback(NetworkCallback) too.
@Override
public void onAvailable(Network network) {
// Do what you need to do here
}
}
Antwoord 2, autoriteit 42%
Ik zal Sayem's
antwoord updaten voor het oplossen van pluisproblemen die aan mij worden getoond.
class ConnectionLiveData(val context: Context) : LiveData<Boolean>() {
private var connectivityManager: ConnectivityManager = context.getSystemService(CONNECTIVITY_SERVICE) as ConnectivityManager
private lateinit var connectivityManagerCallback: ConnectivityManager.NetworkCallback
private val networkRequestBuilder: NetworkRequest.Builder = NetworkRequest.Builder()
.addTransportType(android.net.NetworkCapabilities.TRANSPORT_CELLULAR)
.addTransportType(android.net.NetworkCapabilities.TRANSPORT_WIFI)
override fun onActive() {
super.onActive()
updateConnection()
when {
Build.VERSION.SDK_INT >= Build.VERSION_CODES.N -> connectivityManager.registerDefaultNetworkCallback(getConnectivityMarshmallowManagerCallback())
Build.VERSION.SDK_INT >= Build.VERSION_CODES.M -> marshmallowNetworkAvailableRequest()
Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP -> lollipopNetworkAvailableRequest()
else -> {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
context.registerReceiver(networkReceiver, IntentFilter("android.net.conn.CONNECTIVITY_CHANGE")) // android.net.ConnectivityManager.CONNECTIVITY_ACTION
}
}
}
}
override fun onInactive() {
super.onInactive()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
connectivityManager.unregisterNetworkCallback(connectivityManagerCallback)
} else {
context.unregisterReceiver(networkReceiver)
}
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
private fun lollipopNetworkAvailableRequest() {
connectivityManager.registerNetworkCallback(networkRequestBuilder.build(), getConnectivityLollipopManagerCallback())
}
@TargetApi(Build.VERSION_CODES.M)
private fun marshmallowNetworkAvailableRequest() {
connectivityManager.registerNetworkCallback(networkRequestBuilder.build(), getConnectivityMarshmallowManagerCallback())
}
private fun getConnectivityLollipopManagerCallback(): ConnectivityManager.NetworkCallback {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
connectivityManagerCallback = object : ConnectivityManager.NetworkCallback() {
override fun onAvailable(network: Network?) {
postValue(true)
}
override fun onLost(network: Network?) {
postValue(false)
}
}
return connectivityManagerCallback
} else {
throw IllegalAccessError("Accessing wrong API version")
}
}
private fun getConnectivityMarshmallowManagerCallback(): ConnectivityManager.NetworkCallback {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
connectivityManagerCallback = object : ConnectivityManager.NetworkCallback() {
override fun onCapabilitiesChanged(network: Network?, networkCapabilities: NetworkCapabilities?) {
networkCapabilities?.let { capabilities ->
if (capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) && capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)) {
postValue(true)
}
}
}
override fun onLost(network: Network?) {
postValue(false)
}
}
return connectivityManagerCallback
} else {
throw IllegalAccessError("Accessing wrong API version")
}
}
private val networkReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
updateConnection()
}
}
private fun updateConnection() {
val activeNetwork: NetworkInfo? = connectivityManager.activeNetworkInfo
postValue(activeNetwork?.isConnected == true)
}
}
En hetzelfde gebruik:
val connectionLiveData = ConnectionLiveData(context)
connectionLiveData.observe(this, Observer { isConnected ->
isConnected?.let {
// do job
}
})
Trouwens, bedankt Sayem voor je oplossing.
Antwoord 3, autoriteit 27%
In de documentatie voor Android N staat:
Apps die Android N targeten, ontvangen geen CONNECTIVITY_ACTION
uitzendingen, zelfs als ze manifest-items hebben om om kennisgeving te vragen
van deze evenementen. Apps die op de voorgrond draaien, kunnen nog steeds luisteren naar
CONNECTIVITY_CHANGE op hun hoofdthread als ze om een melding vragen
met een BroadcastReceiver.
Dit betekent dat je nog steeds een BroadcastReceiver
kunt registreren als je app op de voorgrond draait, om veranderingen in de netwerkconnectiviteit te detecteren.
Antwoord 4, autoriteit 6%
Ik kwam een paar dagen geleden hetzelfde probleem tegen en besloot deze bibliotheek te gebruiken Android-Job
Deze bibliotheek gebruikt JobSchedular
, GcmNetworkManager
en BroadcastReceiver
, afhankelijk van op welke Android-versie de app draait.
Een baan starten is vrij eenvoudig
new JobRequest.Builder(DemoSyncJob.TAG)
.setRequiresCharging(true)
.setRequiresDeviceIdle(false)
.setRequiredNetworkType(JobRequest.NetworkType.CONNECTED) // this is what gets the job done
.build()
.schedule();
Antwoord 5, autoriteit 4%
Ik heb een Kotlin-implementatie geschreven die is gebaseerd op Sayam’s antwoordmaar zonder LiveData
. Ik besloot de (op dit moment) nieuwste API-methode te gebruiken (ConnectivityManager#registerDefaultNetworkCallback
) die gericht is op Android Nougat.
/**
* Observes network connectivity by consulting the [ConnectivityManager].
* Observing can run infinitely or automatically be stopped after the first response is received.
*/
class ConnectivityObserver @JvmOverloads constructor(
val context: Context,
val onConnectionAvailable: () -> Unit,
val onConnectionLost: () -> Unit = {},
val shouldStopAfterFirstResponse: Boolean = false
) {
private val connectivityManager
get() = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
@Suppress("DEPRECATION")
private val intentFilter = IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION)
private val broadCastReceiver = object : BroadcastReceiver() {
@Suppress("DEPRECATION")
override fun onReceive(context: Context?, intent: Intent?) {
if (ConnectivityManager.CONNECTIVITY_ACTION != intent?.action) {
return
}
val networkInfo = connectivityManager.activeNetworkInfo
if (networkInfo != null && networkInfo.isConnectedOrConnecting) {
onConnectionAvailable.invoke()
} else {
onConnectionLost.invoke()
}
if (shouldStopAfterFirstResponse) {
stop()
}
}
}
private lateinit var networkCallback: ConnectivityManager.NetworkCallback
init {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
networkCallback = object : ConnectivityManager.NetworkCallback() {
override fun onAvailable(network: Network) {
super.onAvailable(network)
onConnectionAvailable.invoke()
if (shouldStopAfterFirstResponse) {
stop()
}
}
override fun onLost(network: Network?) {
super.onLost(network)
onConnectionLost.invoke()
if (shouldStopAfterFirstResponse) {
stop()
}
}
}
}
}
fun start() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
// Decouple from component lifecycle, use application context.
// See: https://developer.android.com/reference/android/content/Context.html#getApplicationContext()
context.applicationContext.registerReceiver(broadCastReceiver, intentFilter)
} else {
connectivityManager.registerDefaultNetworkCallback(networkCallback)
}
}
fun stop() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
context.applicationContext.unregisterReceiver(broadCastReceiver)
} else {
connectivityManager.unregisterNetworkCallback(networkCallback)
}
}
}
Gebruik:
val onConnectionAvailable = TODO()
val connectivityObserver = ConnectivityObserver(context, onConnectionAvailable)
connectivityObserver.start()
connectivityObserver.stop()
of:
val onConnectionAvailable = TODO()
val onConnectionLost = TODO()
ConnectivityObserver(context,
onConnectionAvailable,
onConnectionLost,
shouldStopAfterFirstResponse = true
).start()
Vergeet niet de machtiging ACCESS_NETWORK_STATE
toe te voegen aan uw AndroidManifest.xml:
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
Ik kijk ernaar uit om nuttige opmerkingen en verbeteringen van u te lezen.
Antwoord 6, autoriteit 2%
Apps die Android N (Nougat) targeten, ontvangen geen CONNECTIVITY_ACTION
-uitzendingen die zijn gedefinieerd in het manifest (zie Svelte).
Mogelijke oplossingen:
- Registreer expliciet een netwerkcallback met
ConnectivityManager.registernetworkCallback()
zodra de applicatie actief is. - Gebruik een
JobScheduler
, en specificeer een onbeperkt netwerk viasetRequiredNetworkType()
.
Zie ook Android O – Verbindingsverandering op de achtergrond detecteren
Antwoord 7
Hier is mijn oplossing in Java! van Android LOLLIPOP tot Android S en hoger
@RequiresApi (api = Build.VERSION_CODES.LOLLIPOP)
public final class NetworkWatcher extends LiveData<Boolean> {
// Variables
private final Context context;
private final ConnectivityManager connectivityManager;
private ConnectivityManager.NetworkCallback networkCallback;
private NetworkRequest networkRequest;
private NetworkWatcher.NetworkStateWatcherReceiver networkStateWatcherReceiver;
// Constructors
public NetworkWatcher(@NonNull Context context){
this.context = context;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){
this.connectivityManager = context.getSystemService(ConnectivityManager.class);
this.networkCallback = new ConnectivityManager.NetworkCallback(){
@Override
public void onLost(@NonNull Network network) {
NetworkWatcher.super.postValue(false);
}
@Override
public void onCapabilitiesChanged(@NonNull Network network, @NonNull NetworkCapabilities networkCapabilities) {
NetworkWatcher.super.postValue(
networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) &&
networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)
);
}
};
this.networkRequest = new NetworkRequest.Builder()
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
.addTransportType(NetworkCapabilities.TRANSPORT_VPN)
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
.addCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)
.build();
} else {
this.networkStateWatcherReceiver = new NetworkStateWatcherReceiver();
this.networkStateWatcherReceiver.setOnNetworkChangedListener(NetworkWatcher.super::postValue);
}
}
// Override methods
@Override
protected void onActive() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S){
this.connectivityManager.registerBestMatchingNetworkCallback(this.networkRequest, this.networkCallback, null);
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N){
this.connectivityManager.registerDefaultNetworkCallback(this.networkCallback);
} else {
this.connectivityManager.registerNetworkCallback(this.networkRequest, this.networkCallback);
}
} else {
this.context.registerReceiver(
this.networkStateWatcherReceiver,
new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION)
);
}
}
@Override
protected void onInactive() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){
this.connectivityManager.unregisterNetworkCallback(this.networkCallback);
} else {
this.context.unregisterReceiver(this.networkStateWatcherReceiver);
}
}
// Inner method classes
@TargetApi(Build.VERSION_CODES.LOLLIPOP_MR1)
private static final class NetworkStateWatcherReceiver extends BroadcastReceiver {
// Variables
private NetworkStateWatcherReceiver.OnNetworkChangedListener onNetworkChangedListener;
// Constructors
public NetworkStateWatcherReceiver() {
}
// Override methods
@Override
public void onReceive(@NonNull Context context, @NonNull Intent intent) {
if (this.onNetworkChangedListener != null) {
boolean isConnected = this.isConnected(context);
this.onNetworkChangedListener.onNetworkChangedListener(isConnected);
}
}
// Methods
private boolean isConnected(@NonNull Context context){
ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();
return networkInfo != null && networkInfo.isConnected();
}
public void setOnNetworkChangedListener(@Nullable OnNetworkChangedListener onNetworkChangedListener) {
this.onNetworkChangedListener = onNetworkChangedListener;
}
// Inner interfaces
private interface OnNetworkChangedListener{
void onNetworkChangedListener(boolean isConnected);
}
}
}
Gebruik het in je hoofdactiviteit binnen de onCreate-methode
new NetworkWatcher(this).observe(this, aBoolean -> {
if (aBoolean){
// Internet connection available
} else {
// No internet connection
}
});
Antwoord 8
Je kunt gemakkelijk de bibliotheek com.github.vladan29:internet_checker:1.0.3 gebruiken.
Met die bibliotheek hoef je geen reactief programmeren te kennen en na te denken over het verwijderen van waarnemers. Slechts een paar regels code zorgen voor een continue en veilige controle van de internetverbinding.
Je kunt alle benodigde instructies vinden op: https:// github.com/vladan29/internet_checker/blob/master/README.md#internet_checker
Antwoord 9
Niets bijzonders hierin. Ik heb zojuist het bovenstaande antwoord naar java omgezet omdat er geen antwoorden zijn met java.
public class ConnectivityWatcher extends LiveData<Boolean> {
private static final String TAG = "ConnectivityWatcher";
private final ConnectivityManager connectivityManager;
private ConnectivityManager.NetworkCallback connectivityManagerCallback;
private final NetworkRequest.Builder networkRequestBuilder;
@NotNull
private final Context context;
protected void onActive() {
super.onActive();
this.updateConnection();
if (Build.VERSION.SDK_INT >= 24) {
try {
this.connectivityManager.registerDefaultNetworkCallback(this.getConnectivityMarshmallowManagerCallback());
} catch (IllegalAccessException e) {
e.printStackTrace();
}
} else if (Build.VERSION.SDK_INT >= 23) {
try {
this.marshmallowNetworkAvailableRequest();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
} else if (Build.VERSION.SDK_INT >= 21) {
try {
this.lollipopNetworkAvailableRequest();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
protected void onInactive() {
super.onInactive();
Log.e(TAG, "onInactive: I am inActive ");
if (Build.VERSION.SDK_INT >= 21) {
connectivityManager.unregisterNetworkCallback(connectivityManagerCallback);
}
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
private void lollipopNetworkAvailableRequest() throws IllegalAccessException {
this.connectivityManager.registerNetworkCallback(this.networkRequestBuilder.build(), this.getConnectivityLollipopManagerCallback());
}
@TargetApi(Build.VERSION_CODES.M)
private void marshmallowNetworkAvailableRequest() throws IllegalAccessException {
this.connectivityManager.registerNetworkCallback(this.networkRequestBuilder.build(), this.getConnectivityMarshmallowManagerCallback());
}
private ConnectivityManager.NetworkCallback getConnectivityLollipopManagerCallback() throws IllegalAccessException {
if (Build.VERSION.SDK_INT >= 21) {
this.connectivityManagerCallback = new ConnectivityManager.NetworkCallback() {
public void onAvailable(@NotNull Network network) {
postValue(true);
}
public void onLost(@NotNull Network network) {
postValue(false);
}
};
return this.connectivityManagerCallback;
} else {
throw new IllegalAccessException();
}
}
private ConnectivityManager.NetworkCallback getConnectivityMarshmallowManagerCallback() throws IllegalAccessException {
if (Build.VERSION.SDK_INT >= 23) {
this.connectivityManagerCallback = new ConnectivityManager.NetworkCallback() {
public void onCapabilitiesChanged(@NotNull Network network, @NotNull NetworkCapabilities networkCapabilities) {
if (connectivityManager != null) {
NetworkCapabilities capabilities = connectivityManager.getNetworkCapabilities(connectivityManager.getActiveNetwork());
if (capabilities != null) {
if (capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) && capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)) {
postValue(true);
}
}
}
}
public void onLost(@NotNull Network network) {
postValue(false);
}
};
return this.connectivityManagerCallback;
} else {
throw new IllegalAccessException();
}
}
private void updateConnection() {
boolean isConnected;
NetworkInfo activeNetwork = this.connectivityManager.getActiveNetworkInfo();
if (activeNetwork != null) {
isConnected = activeNetwork.isConnected();
} else {
isConnected = false;
}
this.postValue(isConnected);
}
@NotNull
public final Context getContext() {
return this.context;
}
public ConnectivityWatcher(@NotNull Context context) {
this.context = context;
ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
if (cm == null) {
throw new NullPointerException("null cannot be cast to non-null type android.net.ConnectivityManager");
} else {
this.connectivityManager = cm;
this.networkRequestBuilder = (new NetworkRequest.Builder()).addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR).addTransportType(NetworkCapabilities.TRANSPORT_WIFI).addTransportType(NetworkCapabilities.TRANSPORT_VPN);
}
}
}
Antwoord 10
Hoewel het negeren van onAvailable(Network network)
soms werkt, kan het zijn dat wanneer onAvailable() wordt aangeroepen, het nieuwe netwerk nog niet volledig functioneel is. Ik heb uiteindelijk het volgende gebruikt volgens dit document https://developer.android. com/reference/android/net/ConnectivityManager.OnNetworkActiveListener
connectivityManager.addDefaultNetworkActiveListener()