web-dev-qa-db-fra.com

Détecter le changement d'état du réseau à l'aide de JobSchedulers dans Android

Avec Android N, vous ne pouvez pas enregistrer statiquement un récepteur de diffusion pour l'intention CONNECTIVITY_CHANGE.

De http://developer.Android.com/preview/features/background-optimization.html#connectivity-action La documentation de Google suggère d'utiliser des Job Schedulers pour effectuer cette tâche.

Est-il possible de détecter un changement d'état du réseau (LTE en wifi) et vice versa en utilisant Job Schedulers dans Android?

16
Mrunal

Oui et non.

La méthode JobInfo.Builder.setRequiredNetworkType() vous permet de planifier des travaux à exécuter lorsque des conditions réseau spécifiques sont remplies.

Le type de réseau peut prendre l'une des trois valeurs suivantes:

  • JobInfo.NETWORK_TYPE_NONE: Aucune connectivité réseau requise.
  • JobInfo.NETWORK_TYPE_UNMETERED: Une connexion non mesurée WiFi ou Ethernet.
  • JobInfo.NETWORK_TYPE_ANY: Toute connexion réseau (WiFi ou cellulaire).

Maintenant, le hic ... il n'y a pas de NETWORK_TYPE_CELLUAR. Vous ne pouvez pas faire en sorte que votre application ne se réveille que lorsqu'elle est uniquement sur le cellulaire. (Pourquoi voudriez-vous faire ça?)

L'autre hic ... les connexions WiFi peuvent être mesurées ou non. Les connexions mesurées sont généralement des choses comme les points d'accès mobiles, et cela peut être détecté automatiquement (il existe une option DHCP spéciale que le point d'accès peut envoyer), ou l'utilisateur peut le basculer manuellement sur une base par réseau à partir des paramètres WiFi.

Donc, oui, vous pouvez définir des contraintes de type réseau sur votre travail JobScheduler. Cependant, non, vous n'obtenez pas le niveau de granularité que vous demandez.

Comme l'a mentionné @CommonsWare, l'idée est que vous voulez généralement planifier des travaux liés au réseau pour qu'ils se produisent lorsque la connectivité réseau n'est pas mesurée, sauf si vous avez une bonne raison. (C'est également une bonne idée de reporter les travaux jusqu'à ce que l'alimentation secteur soit disponible, en utilisant setRequiresCharging(true), pour économiser la batterie.)

14
Trevor Johns

Ce n'est peut-être pas la meilleure solution. Veuillez expliquer pourquoi avant de voter contre.

J'ai utilisé GcmTaskService pour détecter un changement d'état du réseau à l'aide du code suivant. C'est pour une application météo que je développe.

public class ServiceUpdateWeather extends GcmTaskService {

    private static final String TAG = ServiceUpdateWeather.class.getSimpleName();

    public static final String GCM_TAG_REPEAT_CONNECTIVITY_CHANGE = "UPDATE_WEATHER_CONNECTIVITY_CHANGE";

    @Override
    public void onCreate() {
        super.onCreate();
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
    }

    @Override
    public void onInitializeTasks() {
        //called when app is updated to a new version, reinstalled etc.
        //you have to schedule your repeating tasks again
        super.onInitializeTasks();
        if (Utilities.checkIsNougat()) {
            ServiceUpdateWeather.cancelConnectivityChange(getApplicationContext());
            ServiceUpdateWeather.scheduleConnectivityChange(getApplicationContext());
        }
    }

    @Override
    public int onRunTask(TaskParams taskParams) {
        Handler h = new Handler(getMainLooper());
        if(taskParams.getTag().equals(GCM_TAG_REPEAT_CONNECTIVITY_CHANGE)) {
            Log.i(TAG, "Connectivity changed task fired");
            h.post(new Runnable() {
                    @Override
                    public void run() {
                        Toast.makeText(ServiceUpdateWeather.this, "Updating weather", Toast.LENGTH_SHORT).show();
                    }
                });
            WeatherHelper.runNetworkConnectedUpdater(ServiceUpdateWeather.this);
        }

        return GcmNetworkManager.RESULT_SUCCESS;
    }

    public static void scheduleConnectivityChange(Context context) {
        try {
            PeriodicTask connectivityChange = new PeriodicTask.Builder()
                    //specify target service - must extend GcmTaskService
                    .setService(ServiceUpdateWeather.class)
                    //repeat every 30 seconds
                    .setPeriod(30)
                    //specify how much earlier the task can be executed (in seconds)
                    .setFlex(10)
                    //tag that is unique to this task (can be used to cancel task)
                    .setTag(GCM_TAG_REPEAT_CONNECTIVITY_CHANGE)
                    //whether the task persists after device reboot
                    .setPersisted(true)
                    //if another task with same tag is already scheduled, replace it with this task
                    .setUpdateCurrent(true)
                    //set required network state, this line is optional
                    .setRequiredNetwork(Task.NETWORK_STATE_CONNECTED)
                    //request that charging must be connected, this line is optional
                    .setRequiresCharging(false)
                    .build();
            GcmNetworkManager.getInstance(context).schedule(connectivityChange);
            Log.i(TAG, "Connectivity change task scheduled");
        } catch (Exception e) {
            Log.e(TAG, "Connectivity change task failed to schedule");
            e.printStackTrace();
        }
    }

    public static void cancelConnectivityChange(Context context) {
        GcmNetworkManager.getInstance(context).cancelTask(GCM_TAG_REPEAT_CONNECTIVITY_CHANGE, ServiceUpdateWeather.class);
        Log.v(TAG, "Connectivity change task cancelled");
    }
}

Cela semble bien fonctionner pour moi. Il ne détecte pas immédiatement le changement de connectivité comme le fait le récepteur de diffusion. Mais il fonctionne toutes les 30 secondes si une connexion réseau est disponible. Assurez-vous d'appeler

if (Utilities.checkIsNougat()) {
    ServiceUpdateWeather.cancelConnectivityChange(getApplicationContext());
    ServiceUpdateWeather.scheduleConnectivityChange(getApplicationContext());
}

dans votre activité principale onCreate méthode lors du premier lancement de l'application pour planifier cette tâche pour la première fois.

3
Vajira Lasantha