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("当前没网了-> 加载缓存展示一下")
}
}
来自:https://juejin.cn/post/7107833324059492383
最后
如果想要成为架构师或想突破20~30K薪资范畴,那就不要局限在编码,业务,要会选型、扩展,提升编程思维。此外,良好的职业规划也很重要,学习的习惯很重要,但是最重要的还是要能持之以恒,任何不能坚持落实的计划都是空谈。
如果你没有方向,这里给大家分享一套由阿里高级架构师编写的《Android八大模块进阶笔记》,帮大家将杂乱、零散、碎片化的知识进行体系化的整理,让大家系统而高效地掌握Android开发的各个知识点。
相对于我们平时看的碎片化内容,这份笔记的知识点更系统化,更容易理解和记忆,是严格按照知识体系编排的。
全套视频资料:
一、面试合集
二、源码解析合集
三、开源框架合集
欢迎大家一键三连支持,若需要文中资料,直接点击文末CSDN官方认证微信卡片免费领取