Monitoring network status changes — combining registerNetworkCallback and broadcast (kotlin)

illustrate
Android Android monitors network status changes. In applications, we generally need to monitor changes in device network status and make corresponding business processing. We need a convenient and global monitoring implementation. .
Use different API methods for different device system versions;
Pay attention to the adaptation problem of using broadcast to monitor network status in higher versions;

1. Build.VERSION.SDK_INT >= Build.VERSION_CODES.N, use the connectivityManager.registerDefaultNetworkCallback() method;
2. Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP, use connectivityManager.registerNetworkCallback(networkRequest, new MyNetworkCallback()); method;
3. Other system versions use broadcast monitoring;
4. NetworkListenerHelper can add multiple page listeners. When a page needs to monitor the network, it can be added to the listener collection. The listener can be removed when the page is closed. You can also use the event bus;

Core implementation

NetworkListenerHelper

package com.let.networkstatusmonitor
 
import android.annotation.SuppressLint
import android.content.Context
import android.content.IntentFilter
import android.net.ConnectivityManager
import android.net.ConnectivityManager.NetworkCallback
import android.net.Network
import android.net.NetworkCapabilities
import android.net.NetworkRequest
import android.os.Build
import com.let.networkstatusmonitor.NetworkBroadcastReceiver.NetworkBroadcastCallback
import com.let.networkstatusmonitor.NetworkUtils.getNetWorkState
import java.util.concurrent.CopyOnWriteArrayList
 
/**
 * @Author: let
 * @date: 2022/11/15 17:29
 * @description: The monitoring class for network status changes. According to different versions of Android systems, there are two implementation methods: [ConnectivityManager.registerNetworkCallback] and registration broadcast;
 */
object NetworkListenerHelper {
    private val TAG = "NetworkListenerHelper"
    private var mContext: Context? = null
 
    @Volatile
    private var mListenerList: CopyOnWriteArrayList<NetworkConnectedListener>? = null
 
    /**
     * Register for monitoring network status;
     */
    @SuppressLint("MissingPermission")
    fun registerNetworkListener() {
        when {
            Build.VERSION.SDK_INT >= Build.VERSION_CODES.N -> {
                val connectivityManager =
                    mContext!!.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
                if (connectivityManager == null) {
                    LogUtils.el(
                        TAG,
                        "registerNetworkListener#return#connectivityManager=$connectivityManager"
                    )
                    return
                }
                connectivityManager.registerDefaultNetworkCallback(MyNetworkCallback())
            }
            Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP -> {
                val connectivityManager = mContext
                    .getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
                if (connectivityManager == null) {
                    LogUtils.el(
                        TAG,
                        "registerNetworkListener#return#connectivityManager=$connectivityManager"
                    )
                    return
                }
                val builder: NetworkRequest.Builder
                builder = NetworkRequest.Builder()
                builder.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
                    .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
                val networkRequest = builder.build()
                connectivityManager.registerNetworkCallback(networkRequest, MyNetworkCallback())
            }
            else -> {
                // Monitor the network through broadcast;
                val mNetworkBroadcastReceiver = NetworkBroadcastReceiver()
                val filter = IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION)
                mContext!!.registerReceiver(mNetworkBroadcastReceiver, filter)
                mNetworkBroadcastReceiver.setBroadcastCallback(object : NetworkBroadcastCallback {
                    override fun onNetworkBroadcastCallback(
                        isConnected: Boolean,
                        networkStatus: NetworkStatus?
                    ) {
                        //
                        notifyAllListeners(isConnected, networkStatus!!)
                    }
                })
            }
        }
    }
 
    /**
     * Notify all recipients;
     *
     * @param isConnected
     * @param networkStatus
     */
    private fun notifyAllListeners(
        isConnected: Boolean,
        networkStatus: NetworkStatus
    ) {
        if (CollectionUtils.isNotEmpty(mListenerList)) {
// mListenerList.stream().forEach(networkConnectedListener -> {
// networkConnectedListener.onNetworkConnected(isConnected, networdStatus);
// });
            for (listener in mListenerList!!) {
                listener?.onNetworkConnected(isConnected, networkStatus)
            }
        }
    }
 
    /**
     * Add a callback listener;
     */
    @Synchronized
    fun addListener(listener: NetworkConnectedListener?) {
        if (listener == null) {
            return
        }
        if (mListenerList == null) {
            mListenerList = CopyOnWriteArrayList()
        }
        // Prevent duplicate addition;
        if (!mListenerList!!.contains(listener)) {
            mListenerList!!.add(listener)
        }
    }
 
    /**
     * Remove a callback instance;
     *
     * @param listener
     */
    @Synchronized
    fun removeListener(listener: NetworkConnectedListener?) {
        if (listener != null & amp; & amp; CollectionUtils.isNotEmpty(mListenerList)) {
            mListenerList!!.remove(listener)
        }
    }
 
    fun unregisterNetworkCallback() {
        if (mContext == null) {
            return
        }
        val connectivityManager = mContext
            .getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
        if (connectivityManager == null) {
            LogUtils.el(
                TAG,
                "registerNetworkListener#return#connectivityManager=$connectivityManager"
            )
            return
        }
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            connectivityManager.unregisterNetworkCallback(NetworkCallback())
        }
    }
 
    interface NetworkConnectedListener {
        /**
         * @param isConnected
         * @param networkStatus
         */
        fun onNetworkConnected(
            isConnected: Boolean,
            networkStatus: NetworkStatus?
        )
    }
 
    @SuppressLint("NewApi") My
    private class MyNetworkCallback : NetworkCallback() {
        //Both functions serve as default callbacks when the user is connected (or disconnected) from a network (can be WiFi or cellular);
        override fun onAvailable(network: Network) {
            super.onAvailable(network)
            LogUtils.d(TAG, "onAvailable#network=$network")
            //Need to obtain network status synchronously;
            val netWorkState = getNetWorkState(mContext!!)
            LogUtils.d(TAG, "onAvailable#netWorkState=$netWorkState")
            //
            notifyAllListeners(true, netWorkState)
        }
 
        override fun onLost(network: Network) {
            super.onLost(network)
            LogUtils.d(TAG, "onLost#network=$network")
            //Need to obtain network status synchronously;
            val netWorkState = getNetWorkState(mContext!!)
            LogUtils.d(TAG, "onLost#netWorkState=$netWorkState")
            //
            notifyAllListeners(false, netWorkState)
        }
 
        override fun onCapabilitiesChanged(
            network: Network,
            networkCapabilities: NetworkCapabilities
        ) {
            super.onCapabilitiesChanged(network, networkCapabilities)
            LogUtils.d(TAG, "onCapabilitiesChanged#network=$network")
            // LogUtils.d(TAG, "onCapabilitiesChanged#network=" + network + ", networkCapabilities=" + networkCapabilities);
            // Indicates that it can communicate with the Internet (this is true to indicate that it can access the Internet)
            if (networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)) {
                when {
                    networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> {
                        LogUtils.d(TAG, "onCapabilitiesChanged#The network type is wifi")
                    }
                    networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> {
                        LogUtils.d(TAG, "onCapabilitiesChanged#Cellular Network")
                    }
                    else -> {
                        LogUtils.d(TAG, "onCapabilitiesChanged#Other networks")
                    }
                }
            }
        }
    }
 
    fun init(context: Context): NetworkListenerHelper {
        mContext = context
        return this
    }
}

MainActivity

package com.let.networkstatusmonitor
 
import android.os.Bundle
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import com.let.networkstatusmonitor.NetworkListenerHelper.NetworkConnectedListener
 
/**
 * @Author: let
 * @date: 2021/11/15 17:29
 * @description:
 */
class MainActivity : AppCompatActivity(), NetworkConnectedListener {
    private val TAG = "MainActivity"
    private var mTvResult: TextView? = null
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        mTvResult = findViewById(R.id.tv_result)
 
        //Network status callback;
        NetworkListenerHelper.addListener(this@MainActivity)
    }
 
 
    override fun onDestroy() {
        super.onDestroy()
        NetworkListenerHelper.removeListener(this@MainActivity)
    }
 
    override fun onNetworkConnected(isConnected: Boolean, networkStatus: NetworkStatus?) {
        LogUtils.d(TAG, "onNetworkConnected#isConnected=$isConnected")
        val trim = mTvResult!!.text.toString()
        val status = networkStatus.status
        val desc = networkStatus.desc
        mTvResult!!.post { mTvResult!!.text = "\\
Network change notification: status=$status, desc=$desc\\
$trim" }
    }
}

NetworkStatus

package com.let.networkstatusmonitor;
 
/**
 * @Author: let
 * @date: 2022/11/15 17:30
 * @description: Enumeration of network connection status
 */
public enum NetworkStatus {
 
    /**
     *;
     */
    NONE(-1, "No network connection"),
    /**
     * Failed to parse data content
     */
    MOBILE(0, "Mobile network connection"),
    /**
     * Internet problem
     */
    WIFI(1, "WIFI connection");
 
    private int status;
    private String desc;
 
    NetworkStatus(int code, String msg) {
        this.status = code;
        this.desc = msg;
    }
 
    public int getStatus() {
        return status;
    }
 
    public String getDesc() {
        return desc;
    }
 
    @Override
    public String toString() {
        return "NetwordStatus{" +
                "status=" + status +
                ", desc='" + desc + '\'' +
                "} " + super.toString();
    }
}

NetworkUtils

package com.let.networkstatusmonitor
 
import android.annotation.SuppressLint
import android.content.Context
import android.net.ConnectivityManager
import android.net.NetworkCapabilities
import android.os.Build
 
/**
 * @Author: let
 * @date: 2022/11/15 17:31
 * @description:
 */
object NetworkUtils {
    @JvmStatic
    @SuppressLint("MissingPermission")
    fun getNetWorkState(context: Context): NetworkStatus {
        return if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
            val connectivityManager =
                context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
            val mobileNetInfo =
                connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_MOBILE)
            val wifiNetInfo =
                connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI)
            if (mobileNetInfo != null & amp; & amp; mobileNetInfo.isAvailable) {
                //WIFI and mobile network are not connected
                NetworkStatus.MOBILE
            } else if (wifiNetInfo != null & amp; & amp; wifiNetInfo.isAvailable) {
                //WIFI and mobile network are not connected
                NetworkStatus.WIFI
            } else {
                NetworkStatus.NONE
            }
        } else {
            when {
                isMobileConnected(context) -> {
                    NetworkStatus.MOBILE
                }
                isWifiConnected(context) -> {
                    NetworkStatus.WIFI
                }
                else -> {
                    NetworkStatus.NONE
                }
            }
        }
 
// //Get information about all network connections
// Network[] networks = connMgr.getAllNetworks();
// //Get network information one by one through loop
// for (int i = 0; i < networks.length; i + + ) {
// //Get the NetworkInfo object corresponding to the ConnectivityManager object
// NetworkInfo networkInfo = connMgr.getNetworkInfo(networks[i]);
// if (networkInfo.isConnected()) {
// if (networkInfo.getType() == ConnectivityManager.TYPE_WIFI) {
// return NetwordStatus.WIFI;
// } else if (networkInfo.getType() == ConnectivityManager.TYPE_MOBILE) {
// return NetwordStatus.MOBILE;
// }
// }
// }
    }
 
    /**
     * Determine whether the network is connected
     *
     * @param context
     * @return
     */
    @SuppressLint("MissingPermission")
    fun isOnline(context: Context?): Boolean {
        if (context == null) {
            return false
        }
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
            val connMgr =
                context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
            val networkInfo = connMgr.activeNetworkInfo
            return networkInfo != null & amp; & amp; networkInfo.isAvailable
        } else {
            val connectivityManager = context
                .getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
            val activeNetwork = connectivityManager.activeNetwork ?: return false
            val networkCapabilities =
                connectivityManager.getNetworkCapabilities(activeNetwork)
            if (networkCapabilities != null) {
                return networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)
            }
        }
        return false
    }
 
    @SuppressLint("MissingPermission")
    fun isWifiConnected(context: Context?): Boolean {
        if (context == null) {
            return false
        }
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
            val connectivityManager = context
                .getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
            val networkInfo = connectivityManager
                .getNetworkInfo(ConnectivityManager.TYPE_WIFI)
            if (networkInfo != null) {
                return networkInfo.isAvailable
            }
        } else {
            val connectivityManager = context
                .getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
            val activeNetwork = connectivityManager.activeNetwork ?: return false
            val networkCapabilities =
                connectivityManager.getNetworkCapabilities(activeNetwork)
            if (networkCapabilities != null) {
                return networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)
            }
        }
        return false
    }
 
    @SuppressLint("MissingPermission")
    fun isMobileConnected(context: Context?): Boolean {
        if (context == null) {
            return false
        }
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
            val connectivityManager = context
                .getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
            val networkInfo = connectivityManager
                .getNetworkInfo(ConnectivityManager.TYPE_MOBILE)
            if (networkInfo != null) {
                return networkInfo.isAvailable
            }
        } else {
            val connectivityManager = context
                .getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
            val activeNetwork = connectivityManager.activeNetwork ?: return false
            val networkCapabilities =
                connectivityManager.getNetworkCapabilities(activeNetwork)
            if (networkCapabilities != null) {
                return networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)
            }
        }
        return false
    }
}
NetworkBroadcastReceiver
package com.let.networkstatusmonitor
 
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.net.ConnectivityManager
import android.text.TextUtils
 
/**
 * @Author: let
 * @date: 2021/11/15 17:28
 * @description: Monitoring broadcast of network status
 */
class NetworkBroadcastReceiver : BroadcastReceiver() {
    private val TAG = "NetworkBroadcastReceiver"
    private var mBroadcastCallback: NetworkBroadcastCallback? = null
    override fun onReceive(context: Context, intent: Intent) {
        if (intent.action == null) {
            LogUtils.el(TAG, "onReceive#intent=$intent")
            return
        }
        val action = intent.action
        LogUtils.d(TAG, "onReceive#action=$action")
        if (TextUtils.equals(intent.action, ConnectivityManager.CONNECTIVITY_ACTION)) {
            // request for access;
// if (!XXPermissions.isGrantedPermission(context, Permission.WRITE_EXTacERNAL_STORAGE,
// Permission.READ_EXTERNAL_STORAGE)) {
// }
// NetworkInfo mobNetInfo = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
// NetworkInfo wifiNetInfo = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
// if (!mobNetInfo.isConnected() & amp; & amp; !wifiNetInfo.isConnected()) {
// //Neither WIFI nor mobile network is connected
// netContentListener.netContent(false);
// } else {
// //WIFI connection or mobile network connection
// netContentListener.netContent(true);
// }
            val isOnline = NetworkUtils.isOnline(context)
            val networkStatus = NetworkUtils.getNetWorkState(context)
            LogUtils.d(TAG, "onReceive#isOnline=$isOnline, networdStatus=$networkStatus")
            if (mBroadcastCallback != null) {
                mBroadcastCallback!!.onNetworkBroadcastCallback(isOnline, networkStatus)
            }
        }
    }
 
    fun setBroadcastCallback(broadcastCallback: NetworkBroadcastCallback?) {
        mBroadcastCallback = broadcastCallback
    }
 
    interface NetworkBroadcastCallback {
        /**
         * Return the connection status and network status according to the monitoring results;
         *
         * @param isConnected
         * @param networkStatus
         */
        fun onNetworkBroadcastCallback(
            isConnected: Boolean,
            networkStatus: NetworkStatus?
        )
    }
}

ApplicationSupporter

package com.let.networkstatusmonitor
 
import android.app.Application
 
/**
 * @Author: let
 * @date: 2022/11/15 17:28
 * @description:
 */
class ApplicationSupporter : Application() {
    private val TAG = "ApplicationSupporter"
    override fun onCreate() {
        super.onCreate()
        instance = this
        BaseApplicationHelper.getInstance()
            .initApplicationContext(this)
        //Register network status monitoring;
        NetworkListenerHelper.init(this).registerNetworkListener()
    }
 
    companion object {
        var instance: ApplicationSupporter? = null
    }
}

—————-
Copyright statement: This article is an original article by CSDN blogger “Kezhou Qiujian” and follows the CC 4.0 BY-SA copyright agreement. Please attach the original source link and this statement when reprinting.
Original link: https://blog.csdn.net/qq_36162336/article/details/128494247