Sample code for Android 7.0 to listen for network changes

  • 2021-08-31 08:59:45
  • OfStack

Before Android7.0, when the network before Android system is switched, broadcasts will be sent, and services only need to monitor broadcasts.


public class NetChangeReceiver extends BroadcastReceiver {

  private static final String ANDROID_NET_CHANGE_ACTION = "android.net.conn.CONNECTIVITY_CHANGE";

  @Override
  public void onReceive(Context context, Intent intent) {
    if(intent.getAction().equalsIgnoreCase(ANDROID_NET_CHANGE_ACTION)){
      Toast.makeText(context, "Net Changed", Toast.LENGTH_SHORT).show();
    }
  }
}


<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
  package="com.outman.example.androidtest">

  <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
  <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
  <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>
  <uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>

  <application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:roundIcon="@mipmap/ic_launcher_round"
    android:supportsRtl="true">

    <activity android:name=".MainActivity">
      <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
      </intent-filter>
    </activity>

    <receiver android:name=".NetChangeReceiver">
      <intent-filter >
        <action android:name="android.net.conn.CONNECTIVITY_CHANGE"/>
      </intent-filter>
    </receiver>
  </application>

</manifest>

The above code, in front of Android 7.0 devices, can receive messages when the network is switched. On Android 7.0 and above devices, it cannot be received.

Clearly stated on Android 7.0 behavior change

Android 7.0 removes three implicit broadcasts because implicit broadcasts frequently start applications registered to listen to these broadcasts in the background. Deleting these broadcasts can significantly improve device performance and user experience.

To mitigate these problems, Android 7.0 applies the following optimizations:

Applications developed for Android 7.0 do not receive CONNECTIVITY_ACTION broadcasts, even if they already have manifest entries requesting notification of these events. Applications running in the foreground can still listen for CONNECTIVITY_CHANGE in the main thread if they receive notifications using BroadcastReceiver requests.
The application cannot send or receive ACTION_NEW_PICTURE or ACTION_NEW_VIDEO broadcasts. This optimization will affect all applications, not just those for Android 7.0.

Solution

1. As we all know, there are two ways to register broadcasts, one is in AndroidManifest. xml, and the other is through register method.

As described in the Android documentation, by registering in AndroidManifest. xml, App cannot receive broadcasts both in front and back office. By register, when App is running, it can receive the broadcast.

Note: A BroadcastReceiver registered with Context.registerReceiver() continues to receive these broadcasts while the app is running.


public class MainActivity extends Activity {
  private NetChangeReceiver netChangeReceiver;
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    netChangeReceiver = new NetChangeReceiver();
    registerReceiver(netChangeReceiver, new IntentFilter("android.net.conn.CONNECTIVITY_CHANGE"));
  }

  @Override
  protected void onDestroy() {
    super.onDestroy();
    unregisterReceiver(netChangeReceiver);
  }
}

2. Provides a more stable way

Monitoring Network Connectivity While the App is Running
Apps that are running can still listen for CONNECTIVITY_CHANGE with a registered BroadcastReceiver. However, the ConnectivityManager API provides a more robust method to request a callback only when specified network conditions are met.

NetworkRequest objects define the parameters of the network callback in terms of NetworkCapabilities. You create NetworkRequest objects with the NetworkRequest.Builder class. registerNetworkCallback() then passes the NetworkRequest object to the system. When the network conditions are met, the app receives a callback to execute the onAvailable() method defined in its ConnectivityManager.NetworkCallback class.

The app continues to receive callbacks until either the app exits or it calls unregisterNetworkCallback().


public class MainActivity extends Activity {
  private ConnectivityManager.NetworkCallback networkCallback;
  private ConnectivityManager connectivityManager;
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    networkCallback = new NetworkCallbackImpl();
    NetworkRequest.Builder builder = new NetworkRequest.Builder();
    NetworkRequest request = builder.build();
    connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
    connectivityManager.registerNetworkCallback(request, networkCallback);
  }

  @Override
  protected void onDestroy() {
    super.onDestroy();
    connectivityManager.unregisterNetworkCallback(networkCallback);
  }
  private class NetworkCallbackImpl extends ConnectivityManager.NetworkCallback {
    @Override
    public void onAvailable(Network network) {
      super.onAvailable(network);
      Toast.makeText(getBaseContext(), "onAvailable", Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onLosing(Network network, int maxMsToLive) {
      super.onLosing(network, maxMsToLive);
      Toast.makeText(getBaseContext(), "onLosing", Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onLost(Network network) {
      super.onLost(network);
      Toast.makeText(getBaseContext(), "onLost", Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onCapabilitiesChanged(Network network, NetworkCapabilities networkCapabilities) {
      super.onCapabilitiesChanged(network, networkCapabilities);
      Toast.makeText(getBaseContext(), "onCapabilitiesChanged", Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onLinkPropertiesChanged(Network network, LinkProperties linkProperties) {
      super.onLinkPropertiesChanged(network, linkProperties);
      Toast.makeText(getBaseContext(), "onLinkPropertiesChanged", Toast.LENGTH_SHORT).show();
    }
  }
}

Related articles: