持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第1天,点击查看活动详情
Android开发中的页面监听网络变化的方式
首先Android的App中很多都有类似的效果,如网络变化之后没网络了,取缓存,如果有网络了刷新列表,如果有Wifi了下载插件等等。
那么是如何实现的呢?有人说广播,是的,但是8.0之后安卓收紧了静态广播的定义与接收,如何实现才能兼容版本呢?
一、使用通知容器的方式
实现思路:通过动态广播注册监听网络的变化,通过工具类获取当前网络的类型,通过观察者设计模式通知给每一个已注册的页面。
使用单例模式管理ConnectivityReceiver对象,使用观察者模式通知每一个注册的页面。
观察者模式的通知接口
//通过这个接口回调出去
public interface ConnectivityReceiverListener {
void onNetworkConnectionChanged(boolean isConnected, NetWorkUtil.NetworkType networkType);
}
复制代码
public class ConnectivityReceiver extends BroadcastReceiver {
//Observer的通知集合对象,本质上是接口回调
private List<ConnectivityReceiverListener> mObservers = new ArrayList<>();
//保存以注解方式定义的网络监听方法的Map集合
private static Map<Object, List<NetworkMethodManager>> mAnnotationNetWorkObservers = new HashMap<>();
private long lastTimeMilles = 0;
private NetWorkUtil.NetworkType LAST_TYPE = NetWorkUtil.NetworkType.NETWORK_UNKNOWN;
private static class InstanceHolder {
private static final ConnectivityReceiver INSTANCE = new ConnectivityReceiver();
}
public ConnectivityReceiver() {
super();
}
@Override
public void onReceive(Context context, Intent intent) {
if (ConnectivityManager.CONNECTIVITY_ACTION.equals(intent.getAction())) {
NetWorkUtil.NetworkType networkType = NetWorkUtil.getNetworkType(context);
long currentTimeMillis = System.currentTimeMillis();
//如果这次和上次的相同,那么5秒之内 只能触发一次
if (LAST_TYPE == networkType) {
if (lastTimeMilles == 0) {
doNotifyObserver(networkType);
} else {
if (currentTimeMillis - lastTimeMilles > 5000) {
doNotifyObserver(networkType);
}
}
} else {
doNotifyObserver(networkType);
}
//重新赋值最后一次的网络类型和时间戳
lastTimeMilles = currentTimeMillis;
LAST_TYPE = networkType;
}
}
//具体去执行通知
private void doNotifyObserver(NetWorkUtil.NetworkType networkType) {
//收到变换网络的通知就通过遍历集合去循环回调接口
notifyObservers(networkType);
//通知注解类型
notifyByAnnotation(networkType);
//赋值Application全局的类型
BaseApplication.networkType = networkType;
}
/**
* 注册网络监听
*/
public static void registerReceiver(@NonNull Application application) {
IntentFilter intentFilter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
application.getApplicationContext().registerReceiver(InstanceHolder.INSTANCE, intentFilter);
}
/**
* 取消网络监听
*/
public static void unregisterReceiver(@NonNull Application application) {
application.getApplicationContext().unregisterReceiver(InstanceHolder.INSTANCE);
}
/**
* 注册网络变化Observer
*/
public static void registerObserver(ConnectivityReceiverListener observer) {
if (observer == null)
return;
if (!InstanceHolder.INSTANCE.mObservers.contains(observer)) {
InstanceHolder.INSTANCE.mObservers.add(observer);
}
}
/**
* 取消网络变化Observer的注册
*/
public static void unregisterObserver(ConnectivityReceiverListener observer) {
if (observer == null)
return;
if (InstanceHolder.INSTANCE.mObservers == null)
return;
InstanceHolder.INSTANCE.mObservers.remove(observer);
}
}
复制代码
我们可以在Activity或者Fragment的基类中实现通知的接口,并做好注册的开关
abstract class AbsActivity() : AppCompatActivity(), ConnectivityReceiver.ConnectivityReceiverListener {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView()
mActivity = this
mContext = this.applicationContext
//获取intent传递的数据
if (intent != null) {
getDataFromIntent(intent)
}
/** 管理Activity的栈 */
ActivityManage.addActivity(this)
if (needRegisterNetworkChangeObserver()) {
ConnectivityReceiver.registerObserver(this)
}
init()
}
/**
* 是否需要注册监听网络变换
*/
open protected fun needRegisterNetworkChangeObserver(): Boolean {
return false
}
override fun onNetworkConnectionChanged(isConnected: Boolean, networkType: NetWorkUtil.NetworkType?) {
}
override fun onDestroy() {
super.onDestroy()
ActivityManage.removeActivity(this)
if (needRegisterNetworkChangeObserver()) {
ConnectivityReceiver.unregisterObserver(this)
ConnectivityReceiver.unregisterAnnotationObserver(this)
}
}
}
复制代码
使用的时候先在Application中注册全局的网络变化监听
open class BaseApplication : Application() {
//全局的对象
companion object {
lateinit var networkType: NetWorkUtil.NetworkType //此变量会在网络监听中被动态赋值
//检查当前是否有网络
fun checkHasNet(): Boolean {
return networkType != NetWorkUtil.NetworkType.NETWORK_NO && networkType != NetWorkUtil.NetworkType.NETWORK_UNKNOWN
}
}
override fun onCreate() {
super.onCreate()
//获取到全局的网络状态
networkType = NetWorkUtil.getNetworkType(this@BaseApplication.applicationContext)
//网络监听
ConnectivityReceiver.registerReceiver(this)
}
override fun onTerminate() {
super.onTerminate()
ConnectivityReceiver.unregisterReceiver(this)
}
}
复制代码
然后再Activity中实现监听的方法。
class DemoActivity : BaseVDBActivity<EmptyViewModel, ActivityDemoBinding>() {
...
override fun needRegisterNetworkChangeObserver(): Boolean {
return true
}
override fun onNetworkConnectionChanged(isConnected: Boolean, networkType: NetWorkUtil.NetworkType?) {
toast("网络状态发生了变化:当前网络类型:$networkType")
}
}
复制代码
效果
二、使用注解的方式
我们可以在上面的基础上使用注解的方式,注解添加对应的方法,单独精准的指定哪一种网络情况下调用该方法。
定义一个注解,把指定的方法添加到容器中
/**
* 自定义注解,用于方法上面的,需要方法的容器注解和解注册
* 可以直接把网络变换通知到具体的某一个方法
*/
@Target(ElementType.METHOD) //定义在方法上面的注解 ,和EventBus的方式类似
@Retention(RetentionPolicy.RUNTIME) //定义为运行时,在jvm运行的过程中通过反射获取到注解
public @interface NetWork {
NetWorkUtil.NetworkType netWorkType() default NetWorkUtil.NetworkType.NETWORK_NO;
}
复制代码
用于管理添加方法的容器
/**
* 保存符合条件的网络监听注解的对象
*/
public class NetworkMethodManager {
private Class<?> type; //参数类型
private NetWorkUtil.NetworkType networkType; //网络类型
private Method method; //方法对象
public NetworkMethodManager() {
}
public NetworkMethodManager(Class<?> type, NetWorkUtil.NetworkType networkType, Method method) {
this.type = type;
this.networkType = networkType;
this.method = method;
}
public Class<?> getType() {
return type;
}
public void setType(Class<?> type) {
this.type = type;
}
public NetWorkUtil.NetworkType getNetworkType() {
return networkType;
}
public void setNetworkType(NetWorkUtil.NetworkType networkType) {
this.networkType = networkType;
}
public Method getMethod() {
return method;
}
public void setMethod(Method method) {
this.method = method;
}
}
复制代码
改造ConnectivityReceiver,添加注解相关的代码,绑定,解绑,找到对于的方法,反射执行对应的方法。
/**
* 注册网络变化的annotation的方法对象
*/
public static void registerAnnotationObserver(Object object) {
List<NetworkMethodManager> networkMethodManagers = mAnnotationNetWorkObservers.get(object);
if (networkMethodManagers == null || networkMethodManagers.isEmpty()) {
//以前没有注册过,开始添加
networkMethodManagers = findAnnotationMethod(object);
mAnnotationNetWorkObservers.put(object, networkMethodManagers);
}
}
/**
* 找到类中的全部注解@NetWork的方法
*/
private static List<NetworkMethodManager> findAnnotationMethod(Object object) {
List<NetworkMethodManager> networkMethodManagers = new ArrayList<>();
Class<?> clazz = object.getClass(); //获取当前对象的class对象
Method[] methods = clazz.getMethods(); //获取当前class内部全部的method方法
for (Method method : methods) {
NetWork netWork = method.getAnnotation(NetWork.class); //循环判断取出内部的@NetWork注解
if (netWork == null) continue;
//开始添加到集合
NetworkMethodManager manager = new NetworkMethodManager(null, netWork.netWorkType(), method);
networkMethodManagers.add(manager);
}
return networkMethodManagers;
}
/**
* 解绑网络变化的annotation的方法对象
*/
public static void unregisterAnnotationObserver(Object object) {
if (!mAnnotationNetWorkObservers.isEmpty()) {
//如果不为空,直接移除
mAnnotationNetWorkObservers.remove(object);
}
}
/**
* 通知所有的Observer网络状态变化
*/
private void notifyObservers(NetWorkUtil.NetworkType networkType) {
if (networkType == NetWorkUtil.NetworkType.NETWORK_NO || networkType == NetWorkUtil.NetworkType.NETWORK_UNKNOWN) {
for (ConnectivityReceiverListener observer : mObservers) {
observer.onNetworkConnectionChanged(false, networkType);
}
} else {
for (ConnectivityReceiverListener observer : mObservers) {
observer.onNetworkConnectionChanged(true, networkType);
}
}
}
/**
* 通知注解的方法类型去调用方法
*/
private void notifyByAnnotation(NetWorkUtil.NetworkType networkType) {
Set<Object> keySet = mAnnotationNetWorkObservers.keySet();
for (final Object getter : keySet) {
//获取当前类的全部@NetWork方法
List<NetworkMethodManager> networkMethodManagers = mAnnotationNetWorkObservers.get(getter);
assert networkMethodManagers != null;
if (!networkMethodManagers.isEmpty()) {
for (final NetworkMethodManager manager : networkMethodManagers) {
//逐一匹配对应的
if (manager.getNetworkType() == NetWorkUtil.NetworkType.NETWORK_2G) {
if (networkType == NetWorkUtil.NetworkType.NETWORK_2G || networkType == NetWorkUtil.NetworkType.NETWORK_NO) {
invoke(manager, getter);
}
} else if (manager.getNetworkType() == NetWorkUtil.NetworkType.NETWORK_3G) {
if (networkType == NetWorkUtil.NetworkType.NETWORK_3G || networkType == NetWorkUtil.NetworkType.NETWORK_NO) {
invoke(manager, getter);
}
} else if (manager.getNetworkType() == NetWorkUtil.NetworkType.NETWORK_4G) {
if (networkType == NetWorkUtil.NetworkType.NETWORK_4G || networkType == NetWorkUtil.NetworkType.NETWORK_NO) {
invoke(manager, getter);
}
} else if (manager.getNetworkType() == NetWorkUtil.NetworkType.NETWORK_WIFI) {
if (networkType == NetWorkUtil.NetworkType.NETWORK_WIFI || networkType == NetWorkUtil.NetworkType.NETWORK_NO) {
invoke(manager, getter);
}
} else if (manager.getNetworkType() == NetWorkUtil.NetworkType.NETWORK_UNKNOWN) {
invoke(manager, getter);
} else if (manager.getNetworkType() == NetWorkUtil.NetworkType.NETWORK_NO) {
if (networkType == NetWorkUtil.NetworkType.NETWORK_NO) {
invoke(manager, getter);
}
}
}
}
}
}
/**
* 反射执行的具体注解方法
*/
private void invoke(NetworkMethodManager manager, Object getter) {
Method method = manager.getMethod();
try {
method.invoke(getter);
} catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
}
复制代码
使用注解方法的方式来监听网络
class DemoActivity : BaseVDBActivity<EmptyViewModel, ActivityDemoBinding>() {
...
override fun needRegisterNetworkChangeObserver(): Boolean {
return true
}
// override fun onNetworkConnectionChanged(isConnected: Boolean, networkType: NetWorkUtil.NetworkType?) {
// toast("网络状态发生了变化:当前网络类型:$networkType")
// }
@NetWork(netWorkType = NetWorkUtil.NetworkType.NETWORK_WIFI)
fun activeWifi() {
toast("当前是Wifi状态-> 开始下载插件")
}
@NetWork(netWorkType = NetWorkUtil.NetworkType.NETWORK_NO)
fun activeNoNet() {
toast("当前没网了-> 加载缓存展示一下")
}
}
复制代码
效果:
到处我们就能精准的把网络请求控制到方法层级,在日常开发中我们结合2中方式就能实现全部的网络请求监听效果。
内部还涉及到NetWorkUtils的类,其实就是很普通的网络状态工具类,如果大家有需要,源码在此!
感谢看到这里,如果觉得不错还请点赞
支持
到处完结!