Android全局网络监听框架

在日常项目开发中,我们经常需要根据网络状态或网络类型的变化做出一些动作,可能很多小伙伴和我一样是用过工具类封装一些方法来实现的,而今天我要分享最近学到的更为优雅的实现方式,即监听全局网络变化框架。

我们还是先看下这个框架的项目结构
在这里插入图片描述关于这个架构我们的思路是这样的,以MainActivity这个界面为例

public class MainActivity extends BaseActivity {
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //将需要接收网络状态变化的页面进行注册
        NetworkManager.getDefault().register(this);
    }
    //等接收到系统发出的网络状态变化信号后,通过反射执行标记有@Network注解的方法
    @Network(netType = NetType.AUTO)
    public void network(NetType netType) {
        switch (netType) {
            case WIFI:
                Log.e(Constants.LOG_TAG, "WIFI");
                break;
            case CMNET:
            case CMWAP:
                //有网络
                Log.e(Constants.LOG_TAG, "移动数据连接");
                break;
            case NONE:
                //没有网络
                Log.e(Constants.LOG_TAG, "网络连接失败");
                break;
        }
    }
    @Override
    protected void onDestroy() {
        super.onDestroy();
        //在销毁时反注册,解绑
        NetworkManager.getDefault().unRegister(this);
        NetworkManager.getDefault().unRegisterAll();
    }
}

先写一个网络状态的枚举类(大家可根据需要扩展如:蓝牙等)

public enum  NetType {
    /**
     * 有网络,包括wifi,gprs
     */
    AUTO,
    /**
     * WIFI网络
     */
    WIFI,
    /**
     * pc、笔记本电脑、PDA
     */
    CMNET,
    /**
     * 手机上网
     */
    CMWAP,
    /**
     * 没有网络
     */
    NONE
}

接下来是一个自定义注解,作用在方法之上,而这个方法就是当系统监听到网络状态有变化时我们要做出相应动作的地方。

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Network {
    NetType netType() default NetType.AUTO;
}

以及一个常量类

public class Constants {
    /**
     * log前缀名
     */
    public static final String LOG_TAG = "LuckyMorning";
    /**
     * 系统网络改变广播
     */
    public static final String ANDROID_NET_CHANGE_ACTION = "android.net.conn.CONNECTIVITY_CHANGE";
    /**
     * 跳转设置回调请求标识码
     */
    public static final int SETTING_REQUEST_CODE = 666;
}

和一个网络工具类

public class NetworkUtils {

    /**
     * 网络是否可用
     */
    @SuppressLint("MissingPermission")
    public static boolean isNetWorkAvailable() {
        ConnectivityManager manager = (ConnectivityManager) NetworkManager.getDefault().getApplication().getSystemService(Context.CONNECTIVITY_SERVICE);
        if (manager == null) {
            return false;
        }
        //返回所有网络信息
        NetworkInfo[] infos = manager.getAllNetworkInfo();
        if (infos != null) {
            for (NetworkInfo info : infos) {
                if (info.getState() == NetworkInfo.State.CONNECTED) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * 获取当前的网络类型  -1:没有网络  1:WIFI 2:wap 网络  3:net 网络
     */
    @SuppressLint("MissingPermission")
    public static NetType getNetType() {
        ConnectivityManager manager = (ConnectivityManager) NetworkManager.getDefault().getApplication().getSystemService(Context.CONNECTIVITY_SERVICE);
        if (manager == null) {
            return NetType.NONE;
        }
        //返回所有网络信息
        NetworkInfo networkInfo = manager.getActiveNetworkInfo();
        if (networkInfo == null) {
            return NetType.NONE;
        }

        int nType = networkInfo.getType();
        if (nType == ConnectivityManager.TYPE_MOBILE) {
            if (networkInfo.getExtraInfo().toLowerCase().equals("cmnet")) {
                return NetType.CMNET;
            } else {
                return NetType.CMWAP;
            }
        } else if (nType == ConnectivityManager.TYPE_WIFI) {
            return NetType.WIFI;
        }
        return NetType.NONE;
    }

    /**
     * 打开网络设置界面
     */
    public static void openSetting(Context context,int requestCode){
        Intent intent = new Intent("/");
        ComponentName cm = new ComponentName("com.android.settings","com.android.settings.WirelessSettings");
        intent.setComponent(cm);
        intent.setAction("android.intent.action.VIEW");
        ((Activity)context).startActivityForResult(intent,requestCode);
    }
}

那么我们是如何监听到系统网络状态的变化的呢?

  • 5.0之前版本我们是通过系统发送的广播来监听的,即"android.net.conn.CONNECTIVITY_CHANGE"
  • 5.0及之后版本我们可以通过ConnectivityManager.NetworkCallback这个类来监听

我们来看具体实现,定义一个广播接收者来接收系统发出的网络状态变化广播

public class NetStateReceiver extends BroadcastReceiver {

    private NetType netType;
    private Map<Object, List<MethodManager>> networkList;

    public NetStateReceiver() {
        //初始化没有网络
        this.netType = NetType.NONE;
        networkList = new HashMap<>();
    }

    @Override
    public void onReceive(Context context, Intent intent) {
        if (intent == null || intent.getAction() == null) {
            Log.e(Constants.LOG_TAG, "异常啦");
            return;
        }

        //处理广播事件
        if (intent.getAction().equalsIgnoreCase(Constants.ANDROID_NET_CHANGE_ACTION)) {
            Log.e(Constants.LOG_TAG, "网络发生改变");
            netType = NetworkUtils.getNetType();
            if (NetworkUtils.isNetWorkAvailable()) {
                Log.e(Constants.LOG_TAG, "有网络");
            } else {
                Log.e(Constants.LOG_TAG, "无网络");
            }
        }

        //通知所有注册的方法网络发生了变化
        post(netType);
    }

    /**
     * 同时分发出去
     *
     * @param netType
     */
    public void post(NetType netType) {
        Set<Object> set = networkList.keySet();
        for (final Object getter : set) {
            //所有注解方法
            List<MethodManager> methodList = networkList.get(getter);
            if (methodList != null) {
                //循环每个方法
                for (MethodManager methodManager : methodList) {
                    if (methodManager.getType().isAssignableFrom(netType.getClass())) {
                        switch (methodManager.getNetType()) {
                            case AUTO:
                                invoke(methodManager,getter,netType);
                                break;
                            case WIFI:
                                if (netType == NetType.WIFI || netType == NetType.NONE){
                                    invoke(methodManager,getter,netType);
                                }
                                break;
                            case CMWAP:
                                if (netType == NetType.CMWAP || netType == NetType.NONE){
                                    invoke(methodManager,getter,netType);
                                }
                                break;
                            case CMNET:
                                if (netType == NetType.CMNET || netType == NetType.NONE){
                                    invoke(methodManager,getter,netType);
                                }
                                break;
                            default:
                                break;
                        }
                    }
                }
            }
        }
    }

   //执行标记有NetWork注解的防辐射
    private void invoke(MethodManager methodManager, Object getter, NetType netType) {
        Method execute = methodManager.getMethod();
        try {
            execute.invoke(getter,netType);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }

    public void register(Object object) {
        //获取注册者的所有的网络监听注解方法
        List<MethodManager> managerList = networkList.get(object);
        if (managerList == null) {
            //开始添加方法
            managerList = findAnnotationMethod(object);
            networkList.put(object, managerList);
        }
    }

    //将Activity或Fragment中标记有Network注解的方法缓存到集合
    //object:例如Mactivity
    private List<MethodManager> findAnnotationMethod(Object object) {
        List<MethodManager> managerList = new ArrayList<>();
        Class<?> clazz = object.getClass();

        while (clazz!=null){
            String name = clazz.getName();
            if (name.startsWith("java.") || name.startsWith("android.") || name.startsWith("javax.")){
                break;
            }
            Method[] methods = clazz.getMethods();
            for (Method method : methods) {
                Network network = method.getAnnotation(Network.class);
                if (network == null) {
                    continue;
                }

                //方法返回校验
                Type returnType = method.getGenericReturnType();
                if (!"void".equals(returnType.toString())) {
                    throw new RuntimeException(method.getName() + "方法返回必须是void类型");
                }

                //参数校验
                Class<?>[] parameterTypes = method.getParameterTypes();
                if (parameterTypes.length != 1) {
                    throw new RuntimeException(method.getName() + "方法只能有一个参数");
                }

                //过滤上面,得到符合要求的方法,才开始添加到集合
                //例:对应MainActivity中
                // @Network(netType = NetType.AUTO)
                //public void network(NetType netType) {}
                //parameterTypes[0] :NetType netType
                //network.netType() :NetType.AUTO
                //method  :network
                MethodManager manager = new MethodManager(parameterTypes[0], network.netType(), method);
                managerList.add(manager);

            }
            clazz = clazz.getSuperclass();
        }

        return managerList;
    }

    public void unRegister(Object object) {
        if (!networkList.isEmpty()) {
            networkList.remove(object);
        }
        Log.e(Constants.LOG_TAG, object.getClass().getName() + "解注册成功");
    }

    public void unRegisterAll() {
        if (!networkList.isEmpty()) {
            networkList.clear();
        }
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
            NetworkManager.getDefault().getApplication().unregisterReceiver(this);
        }
        networkList = null;
        Log.e(Constants.LOG_TAG, "全部解注册成功");
    }
}


其中,在注册过程中是以MethodManager对象进行存储的

/**
 * 保存符合要求的网络监听注解方法,封装类
 */
public class MethodManager {
    /**
     * 参数类型 NetType
     */
    private Class<?> type;
    /**
     * 方法名
     */
    private Method method;
    /**
     * 网络类型
     */
    private NetType netType;

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

    public Class<?> getType() {
        return type;
    }

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

    public Method getMethod() {
        return method;
    }

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

    public NetType getNetType() {
        return netType;
    }

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

在AndroidManifest配置文件中注册广播

        <!-- 网络变化广播 -->
        <receiver android:name="com.zhoumohan.common_library.globalNetWorkChange.NetStateReceiver">
            <intent-filter>
                <action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
            </intent-filter>
        </receiver>

我们通过一个网络管理类来处理系统传出的网络状态

public class NetworkManager {
    private static volatile NetworkManager instance;
    private Application application;
    //处理系统发送的广播,下面会介绍到
    private NetStateReceiver receiver;

    private NetworkManager() {
        receiver = new NetStateReceiver();
    }
    //单例
    public static NetworkManager getDefault() {
        if (instance == null) {
            synchronized (NetworkManager.class) {
                if (instance == null) {
                    instance = new NetworkManager();
                }
            }
        }
        return instance;
    }

    public Application getApplication() {
        if (application == null) {
            throw new RuntimeException("NetworkManager.getDefault().init()未初始化");
        }
        return application;
    }

    @SuppressLint("MissingPermission")
    public void init(Application application) {
        this.application = application;

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            //NetworkCallbackImpl是我们实现的ConnectivityManager.NetworkCallback的子类下面会给出
            ConnectivityManager.NetworkCallback networkCallback = new NetworkCallbackImpl(receiver);
            NetworkRequest.Builder builder = new NetworkRequest.Builder();
            NetworkRequest request = builder.build();
            ConnectivityManager connectivityManager = (ConnectivityManager) NetworkManager.getDefault().getApplication().getSystemService(Context.CONNECTIVITY_SERVICE);
            if (connectivityManager != null) {
                connectivityManager.registerNetworkCallback(request, networkCallback);
            }
        } else {
            //做广播注册
            IntentFilter filter = new IntentFilter();
            filter.addAction(Constants.ANDROID_NET_CHANGE_ACTION);
            application.registerReceiver(receiver, filter);
        }
    }


    public void register(Object object) {
        receiver.register(object);
    }

    public void unRegister(Object object) {
        receiver.unRegister(object);

    }

    public void unRegisterAll() {
        receiver.unRegisterAll();

    }
}

NetworkCallbackImpl

@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public class NetworkCallbackImpl extends ConnectivityManager.NetworkCallback {

    private NetStateReceiver receiver;

    public NetworkCallbackImpl() {
    }

    public NetworkCallbackImpl(NetStateReceiver receiver) {
        this.receiver = receiver;
    }

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

    @Override
    public void onLost(Network network) {
        super.onLost(network);
        Log.e(Constants.LOG_TAG,"网络已中断");
        receiver.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)){
                Log.e(Constants.LOG_TAG,"网络已变更,类型为WIFI");
                receiver.post(NetType.WIFI);

            }else if(networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
                Log.e(Constants.LOG_TAG,"网络已变更,类型为移动数据网络");
                receiver.post(NetType.CMWAP);
            }
        }
    }
}

最后要记得在Application中初始化NetworkManager

public class App extends Application {

    @Override
    public void onCreate() {
        super.onCreate();
        NetworkManager.getDefault().init(this);
    }
}

好,到此我们的全局网络变化监听框架就完成了,下面给出项目地址供小伙伴们学习研究
demo

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值