Android-网络监控框架NetworkCallback + BroadCastReceiver

    Android网络监控可以说是一个老生长谈的话题了。但随着Android API的更新,总有新东西可以聊。我们知道在Android N上移除了部分隐式广播来达到防止应用被频繁启动而提升设备性能的问题。其中就包括:


    
        
    

因此,为了兼容Android N,只能使用动态注册的方式来注册BroadCastReceiver:

 IntentFilter filter = new IntentFilter();
 filter.addAction(Constants.ACTION_CONNECTIVITY_CHANGE);
 application.registerReceiver(receiver, filter);

    但是,这不是今天的重点,今天主要说的是NetworkCallback,这是Android API 21以后推出的api。有人可能会说单单使用动态注册BroadCastReceiver的方式就可以解决的问题,为什么还要使用这个不兼容低版本的api?我们要相信android 5.0及以下的手机逐渐会退出历史舞台的,新版api总归是要用起来的。况且NetworkCallback有着更佳的表现,我们没有拒绝的理由。

    第一步:实现一个NetworkCallback方法:

@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public class NetworkCallbackImpl extends ConnectivityManager.NetworkCallback {
    private static final String TAG = "NetworkCallbackImpl";
    private Map> networkList = new HashMap<>();

    @Override
    public void onAvailable(Network network) {
        super.onAvailable(network);
        Log.e(TAG,"网络连接了");
    }

    @Override
    public void onLost(Network network) {
        super.onLost(network);
        Log.e(TAG,"网络断开了");
    }

    @Override
    public void onCapabilitiesChanged(Network network, NetworkCapabilities networkCapabilities) {
        super.onCapabilitiesChanged(network, networkCapabilities);
        if(networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)){
            if(networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)){
                Log.e(TAG,"wifi网络已连接");
            }else {
                Log.e(TAG,"移动网络已连接");
            }
        }
    }
}

    通过复写以上三个方法基本就可以满足我们监控网络的连接与断开,wifi网络与移动网络切换的需求了。

    第二步:注册NetworkCallbackImpl

NetworkCallbackImpl networkCallback = new NetworkCallbackImpl();
NetworkRequest request = new NetworkRequest.Builder().build();
ConnectivityManager cmgr = (ConnectivityManager) application
        .getSystemService(Context.CONNECTIVITY_SERVICE);
if (cmgr != null) {
    cmgr.registerNetworkCallback(request,networkCallback);
}

    通过以上两步我们就可以run一把代码,不出意外,网络连接状态已经可以愉快的打印出来了。那么问题来了,我们如何在Activity或者是Fragment中实时获取网络状态了呢?很简单,使用接口回调就可以搞定了。当然也可以使用EventBus或者RxBus来进行事件传递。对于没有在项目中使用事件总线的情况,我们不妨来实现自己的"EventBus"。

  1. 先定义一个枚举类型,用来表示网络状态
public enum NetType {
    AUTO,//全部状态
    NONE,//无网络
    WIFI,
    MOBILE
}
  1. 为需要回调网络状态的方法定义一个运行时注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Network {
    NetType netType() default NetType.AUTO;
}
  1. 为Activity中的监控方法添加注解
@Network(netType = NetType.AUTO)
public void onNetChanged(NetType netType) {
    switch (netType) {
        case WIFI:
            Log.e(TAG,"AUTO监控:WIFI CONNECT");
            break;
        case MOBILE:
            Log.e(TAG,"AUTO监控:MOBILE CONNECT");
            break;
        case AUTO:
            Log.e(TAG,"AUTO监控:AUTO CONNECT");
            break;
        case NONE:
            Log.e(TAG,"AUTO监控:NONE CONNECT");
            break;
        default:
            break;
    }
}

@Network(netType = NetType.WIFI)
public void onWifiChanged(NetType netType){
    switch (netType){
        case WIFI:
            Log.e(TAG,"wifi监控:WIFI CONNECT");
            break;
        case NONE:
            Log.e(TAG,"wifi监控:NONE CONNECT");
            break;
    }
}

@Network(netType = NetType.MOBILE)
public void onMobileChanged(NetType netType){
    switch (netType){
        case MOBILE:
            Log.e(TAG,"Mobile监控:MOBILE CONNECT");
            break;
        case NONE:
            Log.e(TAG,"Mobile监控:NONE CONNECT");
            break;
    }
}

    注解和监控方法都定义好了,我们需要将二者关联起来,也就是我们要在NetworkCallback中为Activity提供注册方法。在此之前我们创建一个注解方法的管理类

4.注解方法管理类

public class MethodManager {

    //被注解方法的参数类型 NetType netType
    private Class type;

    //需要监听的网络类型
    private NetType netType;

    //需要执行的方法
    private Method method;

    public MethodManager(Class type, NetType netType, Method method) {
        this.type = type;
        this.netType = netType;
        this.method = method;
    }

    public Class getType() {
        return type;
    }

    public void setType(Class type) {
        this.type = type;
    }

    public NetType getNetType() {
        return netType;
    }

    public void setNetType(NetType netType) {
        this.netType = netType;
    }

    public Method getMethod() {
        return method;
    }

    public void setMethod(Method method) {
        this.method = method;
    }
}

5.通过对注解的解析,在NetworkCallback中为Actvitiy提供注册与解除注册

@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public class NetworkCallbackImpl extends ConnectivityManager.NetworkCallback {
    private static final String TAG = "NetworkCallbackImpl";
    private Map> networkList = new HashMap<>();

    @Override
    public void onAvailable(Network network) {
        super.onAvailable(network);
        Log.e(TAG,"网络连接了");
    }

    @Override
    public void onLost(Network network) {
        super.onLost(network);
        post(NetType.NONE);
    }

    @Override
    public void onCapabilitiesChanged(Network network, NetworkCapabilities networkCapabilities) {
        super.onCapabilitiesChanged(network, networkCapabilities);
        if(networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)){
            if(networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)){
                post(NetType.WIFI);
            }else {
                post(NetType.MOBILE);
            }
        }
    }

    /**
     * 通知所有注册的方法,网络发生了改变
     * @param netType
     */
    private void post(NetType netType) {
        Set sets = networkList.keySet();
        for (Object observer : sets) {
            List methodList = networkList.get(observer);
            for (MethodManager method : methodList) {
                if (method.getType().isAssignableFrom(netType.getClass())) {
                    if (method.getNetType() == netType ||
                            netType == NetType.NONE ||
                            method.getNetType() == NetType.AUTO) {
                        invoke(method, observer, netType);
                    }
                }
            }
        }
    }

    private void invoke(MethodManager methodManager, Object observer, NetType netType) {
        try {
            Method execute = methodManager.getMethod();
            execute.invoke(observer, netType);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }

    /**
     * 注册监听
     * @param observer
     */
    public void registerObserver(Object observer) {
        List methodList = networkList.get(observer);
        if (methodList == null) {
            methodList = getAnnotationMethod(observer);
            networkList.put(observer, methodList);
        }
    }

    /**
     * 遍历注册类中的所有方法,收集被注解方法的信息
     * @param observer
     * @return
     */
    private List getAnnotationMethod(Object observer) {
        List methodList = new ArrayList<>();
        Method[] methods = observer.getClass().getMethods();
        for (Method method : methods) {
            com.px.network.Network network = method.getAnnotation(com.px.network.Network.class);
            if (network == null) {
                continue;
            }
            Log.e(TAG, "NETWORK.....");
            //校验返回值
            Type returnType = method.getGenericReturnType();
            if (!"void".equals(returnType.toString())) {
                throw new RuntimeException(method.getName() + "return type should be null");
            }
            //校验参数
            Class[] parameterTypes = method.getParameterTypes();
            if (parameterTypes.length != 1) {
                throw new RuntimeException(method.getName() + "arguments should be one");
            }

            MethodManager methodManager = new MethodManager(parameterTypes[0],
                    network.netType(), method);
            methodList.add(methodManager);
        }
        return methodList;
    }

    public void unRegisterObserver(Object observer) {
        if (!networkList.isEmpty()) {
            networkList.remove(observer);
        }
    }

    public void unRegisterAllObserver() {
        if (!networkList.isEmpty()) {
            networkList.clear();
        }
        NetworkManager.getInstance().getConnectivityManager().unregisterNetworkCallback(this);
        networkList = null;
    }
}


    这样,整个网络监控框架基本完成,这个框架中使用了注解,通过反射的方式完成了事件了分发,如果你介意使用反射,可以使用接口回调的方式注册事件。完整代码请查看Demo。

你可能感兴趣的:(Android-网络监控框架NetworkCallback + BroadCastReceiver)