2017-01-23 5 views
0

J'ai besoin de surveiller et de déterminer les changements d'état de la connectivité dans mon application Android. Pour cela, je me suis inscrit ma classe en tant que récepteur de radiodiffusion:Conditions de concurrence lors de la détection du changement d'état de la connectivité sous Android

IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION); 
context.registerReceiver(this, filter); 

Maintenant, pour déterminer l'état de la connectivité, vous pouvez effectuer les opérations suivantes:

@Override 
public void onReceive(Context context, Intent intent) { 
    if (!ConnectivityManager.CONNECTIVITY_ACTION.equals(intent.getAction())) { 
    return; 
    } 
    NetworkInfo aNetworkInfo = 
     intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO); 
    if (aNetworkInfo == null) { 
    return; 
    } 

    boolean isConnected = aNetworkInfo.isConnected(); 
    int networkType = aNetworkInfo.getType(); 
    // by using isConnected & networkType, get the new connectivity status.. 
} 

Le problème est que ConnectivityManager.EXTRA_NETWORK_INFO est dépréciée. Maintenant, vous êtes conseillé d'utiliser le CONNECTIVITY_SERVICE avec getActiveNetworkInfo(), quelque chose comme ça:

@Override 
public void onReceive(Context context, Intent intent) { 
    if (!ConnectivityManager.CONNECTIVITY_ACTION.equals(intent.getAction())) { 
    return; 
    } 
    ConnectivityManager connManager = 
     (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); 
    if (connManager == null) { 
    return; 
    } 
    NetworkInfo activeNetworkInfo = connManager.getActiveNetworkInfo(); 
    boolean isConnected = 
     (activeNetworkInfo != null) && activeNetworkInfo.isConnected(); 
    int networkType = 
     (activeNetworkInfo != null) ? activeNetworkInfo.getType() : -1; 
    // by using isConnected & networkType, get the new connectivity status.. 
} 

Cela pose la question suivante:

Dans la 2e mise en œuvre, lors de l'utilisation du CONNECTIVITY_SERVICE et pas le EXTRA_NETWORK_INFO :

Y at-il une chance pour une condition de course? Comme le onReceive est appelé de manière asynchrone, lors de l'obtention des informations réseau du service de connectivité, l'état de connectivité peut-il être différent des informations réseau dans l'intention (car la connectivité peut changer entre-temps)? Signification, lors de l'utilisation de l'intention, je suis sûr que les informations du réseau comprend les données qui ont déclenché le onReceive, mais lors de l'utilisation du service - l'information de réseau pourrait être différente ...?

Si oui, quelle est la meilleure façon d'obtenir l'information qui a déclenché le onReceive? Aussi, si la seule façon de le faire est de continuer à utiliser l'intention - cela ne fait-il pas 2 sources de vérité? (Un du Service de connectivité, et un de l'intention envoyé ...)

MISE À JOUR:

Un exemple de la condition de course possible:

Quelqu'un connecté au WiFi et immédiatement déconnecté du WiFi . Cela entraînera l'envoi de 2 intentions (une pour la connexion au WiFi et une pour la déconnexion du Wi-Fi. Plus d'intentions sont effectivement envoyées, mais je vais me concentrer sur ces 2). La condition de concurrence possible que je pose est la suivante: lorsque nous obtenons la première intention (WiFi connecté), l'intention supplémentaire EXTRA_NETWORK_INFO se traduira par isConnected = true et networkType = TYPE_WIFI. Mais, est-il possible que lorsque je reçois les données du service de connectivité, comme le onReceive est appelé de manière asynchrone, le WiFi s'est déjà déconnecté, résultant en isConnected = false et networkType = TYPE_WIFI alors que l'intention détient toujours les bonnes valeurs pour cet appel de onReceive? Ou cela arrivera toujours assez vite pour que vous obteniez les bonnes valeurs du service de connectivité dans le onReceive ..?

Répondre

0

Ma solution a été d'envoyer un changement de connexion à chaque fois de diffusion en ajoutant un supplément si l'état de la connexion est vers le haut ou vers le bas, espérons qu'il aide:

public class ConnectivityChangeReceiver extends BroadcastReceiver { 

@Override 
public void onReceive(Context context, Intent intent) { 
    Log.i(context.getClass().getName(), " Changed connection "); 
    context.sendBroadcast(new Intent(MyApplication.ACTION_CONNECTION_CHANGED) 
      .putExtra(MyApplication.INTENT_EXTRA_CONNECTION_STATUS,NetWorkUtils.isNetworkAvailable(context))); 
}} 


public static boolean isNetworkAvailable(Context context) { 
    ConnectivityManager cm = 
      (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); 
    NetworkInfo activeNetwork = cm.getActiveNetworkInfo(); 
    return activeNetwork != null && 
      activeNetwork.isConnectedOrConnecting(); 
} 

manifeste Android:

<receiver android:name=".ConnectivityChangeReceiver"> 
     <intent-filter> 
      <action android:name="android.net.conn.CONNECTIVITY_CHANGE" /> 
     </intent-filter> 
    </receiver> 
+0

Encore une fois - vous utilisez le service de connectivité et non l'information dans l'intention envoyée -> ainsi la question demeure (est-ce que l'information du service sera toujours la même que l'information dans l'intention, ou une condition de concurrence pourrait faire que cette information soit différente?) – Guy

+0

bien selon d Vous pouvez utiliser l'extra sur l'intention de connaître l'état du réseau, mais je suis allé pour la solution directe pour vérifier à chaque fois sur recevoir pour être sûr. – AmirG

+0

cochez https://developer.android.com/reference/android/net/ConnectivityManager.html at CONNECTIVITY_ACTION – AmirG