在日常项目开发中,我们经常需要根据网络状态或网络类型的变化做出一些动作,可能很多小伙伴和我一样是用过工具类封装一些方法来实现的,而今天我要分享最近学到的更为优雅的实现方式,即监听全局网络变化框架。
我们还是先看下这个框架的项目结构
关于这个架构我们的思路是这样的,以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);
}
}
那么我们是如何监听到系统网络状态的变化的呢?
我们来看具体实现,定义一个广播接收者来接收系统发出的网络状态变化广播
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配置文件中注册广播
我们通过一个网络管理类来处理系统传出的网络状态
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