简体   繁体   中英

Detect connectivity changes on Android 7.0 Nougat when app is in foreground

Nougat changed the way it handles CONNECTIVITY_CHANGED intents (basically ignoring it, forcing devs to use the job scheduler) so this leaves me wondering:

If I have an app that is in the middle of retrieving some data (and I checked if the phone was online at the time I did the request but the user is on the move and the phone connects to a different wifi access point, for example) and it fails, how do I detect that the connection has been restored and I cam retry fetxhing the data?

So in this case my app is in the foreground, I think Chrome (for android) has a similar function.

Do I need to poll it myself? Or is there some event that is allowed at that time?

While Andromeda's answer could be used, that solution is not Google's intended choice. Your question was what to do when a connection is lost and you need to resume operation when network service returns.

While CONNECTIVITY_CHANGE technically works, it was always a bit of a hack for this specific need and it will stop working in Nougat as soon as your app goes in the background. What you should really use is a job scheduler API. Google has offered us many options with differing requirements and features.

  1. JobScheduler

JobScheduler was added in Lollipop and adds a scheduler which can wait for network connectivity to schedule a job. It can even depend on the kind of connection, checking for unmetered or non-roaming connections. This option has no backwards compatibility, but works without Google Play Services.

  1. GCM Network Manager

GcmNetworkManager is a direct port of the JobScheduler functionality to versions before Lollipop, but it requires Google Play Services. GcmNetworkManager has been mostly deprecated by Firebase Job Dispatcher.

  1. Firebase Job Dispatcher

Firebase JobDispatcher provides another means to schedule jobs for versions before Lollipop, which uses Google Play Services by default, but can be configured to not require this dependency.

  1. WorkManager

I just edited this post to add that Google replaced all of the three previous job schedulers by WorkManager, which is better than the others in almost every way. You can set a required network type for your job to run. You can even chain jobs together one after another.

All of these options will satisfy your need in a battery-friendly manner and your jobs will still get scheduled even if the device wakes up briefly from Doze mode.

Here is more information about the various options with examples provided by Google:

https://developer.android.com/topic/performance/scheduling.html https://developer.android.com/topic/performance/background-optimization.html#sched-jobs

According to doc :

Apps targeting Android 7.0 (API level 24) and higher do not receive CONNECTIVITY_ACTION broadcasts if they declare their broadcast receiver in the manifest. Apps will still receive CONNECTIVITY_ACTION broadcasts if they register their BroadcastReceiver with Context.registerReceiver() and that context is still valid.

Apps that are running can still listen for CONNECTIVITY_CHANGE on their main thread if they request notification with a BroadcastReceiver.

https://developer.android.com/about/versions/nougat/android-7.0-changes.html

In my case I've subscribed to broadcast with CONNECTIVITY_CHANGE filter in Service and it's working.

How to keep Service alive is another story :)

public class ConnectivityReceiver
{

public static boolean getWifiStatus(Context context)
{
    // To get System Connectivity status
    ConnectivityManager cm = (ConnectivityManager) context
            .getSystemService(Context.CONNECTIVITY_SERVICE);


    NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
    if (null != activeNetwork)
    {
        // Check For Wifi Status
        if(activeNetwork.getType() == ConnectivityManager.TYPE_WIFI)
            return true;
        else
            return false;
    }

    return false;
}

public class NetworkMgr extends BroadcastReceiver {

@Override
public void onReceive(Context context, Intent intent) {

    ConnectivityReceiver cf = new ConnectivityReceiver();
    boolean status = cf.getWifiStatus(context);

    if(status)
    {
        Toast.makeText(context,"Wifi Connection is On.", Toast.LENGTH_SHORT).show();
    }
    else
    {
        Toast.makeText(context,"Wifi Connection is Off.", Toast.LENGTH_SHORT).show();
    }
  }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM