一、Android Wifi常用广播

网络开发中主体会使用到的action:

ConnectivityManager.CONNECTIVITY_ACTION
WifiManager.WIFI_STATE_CHANGED_ACTION
WifiManager.SCAN_RESULTS_AVAILABLE_ACTION
WifiManager.NETWORK_IDS_CHANGED_ACTION
WifiManager.SUPPLICANT_STATE_CHANGED_ACTION
WifiManager.CONFIGURED_NETWORKS_CHANGED_ACTION
WifiManager.LINK_CONFIGURATION_CHANGED_ACTION
WifiManager.NETWORK_STATE_CHANGED_ACTION
WifiManager.RSSI_CHANGED_ACTION

1、ConnectivityManager.CONNECTIVITY_ACTION:

      网络连接发生了变化的广播, 通常是默认的连接类型已经建立连接或者已经失去连接会触发的广播; 监听到这个广播之后, 可以从intent中获取字段ConnectivityManager.EXTRA_NO_CONNECTIVITY, 如果返回true, 代表当前连接断开. 否则,连接成功.同时可以从intent中取出字段 ConnectivityManager.EXTRA_NETWORK_INFO, 返回NetWorkInfo, 通过此对象, 你会获取当前连接的一些更为具体的信息. 部分代码如下:

    // 是否无连接.
public static boolean isNoConnectivity(Intent intent) {
return intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false);
} // 获取当前网络信息.
public static NetworkInfo getExtraNetworkInfo(Intent intent) {
return intent.getPacelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO);
} // 获取当前网络状态.
public static NetworkInfo.State getNetState(NetworkInfo info) {
return info == null ? null : info.getState();
} // 获取当前网络类型.
public static int getNetState(NetworkInfo info) {
return info == null ? -1 : info.getType();
}

2、WifiManager.WIFI_STATE_CHANGED_ACTION:

      WiFi模块硬件状态改变的广播, 对于肉眼而言, 看到的直观表征有, WiFi开启, WiFi关闭; 而在实际的过程中, WIFI 从开启到关闭, 或是从关闭到开启, 需要经历三个状态, 以开启WIFI为例, 其要经过的状态分别为: 已关闭, 开启中, 已开启. 关闭WIFI则相反, 分为为: 已开启, 关闭中, 关闭. 接收到这个广播后, 你可以从intent中取出当前WiFi硬件的变化状态, 可以使用 int 值来区别; 这个key是: EXTRA_WIFI_STATE, 可能得到的值为:0, 1, 2, 3, 4; 当然除了这种获取方式, 也可以通过WiFiManager对象getWifiState() 获取这个值. 也可以从 intent 中取出另外一个值, 表示之前WiFi模块的状态, 是不是很爽? 那么, 对应的key, 就是: EXTRA_PREVIOUS_WIFI_STATE;

    // 通过 intent 获取当前WIFI状态.
public static int getWifiStateByIntent(Intent intent) {
return intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, WifiManager.WIFI_STATE_UNKNOWN);
} // 通过 WifiManager 获取当前WIFI状态.
public static int getWifiStateByWifiManager(WifiManager manager) {
return manager == null ? WifiManager.WIFI_STATE_UNKNOWN : manager.getState();
} // 获取WIFI前一时刻状态.
public static int getWifiPreviousState(Intent intent) {
return intent.getIntExtra(WifiManager.EXTRA_PREVIOUS_WIFI_STATE, WifiManager.WIFI_STATE_UNKNOWN);
} 其中:
0 --> WiFiManager.WIFI_STATE_DISABLING, 表示 WiFi 正关闭的瞬间状态;
1 --> WifiManager.WIFI_STATE_DISABLED, 表示 WiFi 模块已经完全关闭的状态;
2 --> WifiManager.WIFI_STATE_ENABLING, 表示 WiFi 模块正在打开中瞬间的状态;
3 --> WiFiManager.WIFI_STATE_ENABLED, 表示 WiFi 模块已经完全开启的状态;
4 --> WiFiManager.WIFI_STATE_UNKNOWN, 表示 WiFi 处于一种未知状态; 通常是在开启或关闭WiFi的过程中出现不可预知的错误, 通常是底层状态机可能跑的出现故障了, 会到这种情况, 与底层控制相关;

3、WifiManager.SCAN_RESULTS_AVAILABLE_ACTION:

      扫描到一个热点, 并且此热点达可用状态 会触发此广播; 此时, 你可以通过wifiManager.getScanResult() 来取出当前所扫描到的ScanResult; 同时, 你可以从intent中取出一个boolean值; 如果此值为true, 代表着扫描热点已完全成功; 为false, 代表此次扫描不成功, ScanResult距离上次扫描并未得到更新;

    // 获取 ScanResult 列表:
public static List<ScanResult> getScanResultForWifi(WifiManager manager) {
return manager == null ? null : manager.getScanResult();
} // result 是否更新:
public static boolean isResultUpdated(Intent intent) {
return intent != null && intent.getBooleanExtra(WifiManager.EXTRA_RESULTS_UPDATED, false);
}

4、WifiManager.NETWORK_IDS_CHANGED_ACTION:

      在网络配置, 保存, 添加, 连接, 断开, 忘记的操作过后, 均会对 WIFI 热点配置形成影响, 在shell下, 如果有root权限, 可以在执行上述动作前后, 分别浏览 /data/misc/wifi/wpa_supplicant.conf 应该是有本质的变化, 此时会收到此广播.具体的执行指令为:

    adb shell
$ cat /data/misc/wifi/wpa_supplicant.conf

5、WifiManager.SUPPLICANT_STATE_CHANGED_ACTION:

      建立连接的热点正在发生变化. 象征变化的相关类为: SupplicantState, 你可以在接收到此广播时, 观察到已经建立连接的热点的整个连接过程, 包含可能会出现连接错误的错误码. 相关代码为:

    // 获取当前网络新状态.
public static SupplicantState getCurrentNetworkState(Intent intent) {
return intent.getParcelableExtra(WifiManager.EXTRA_NEW_STATE);
} // 获取当前网络连接状态码.
public static int getCurrentNetworkCode(Intent intent) {
return int netConnectErrorCode = intent.getIntExtra(WifiManager.EXTRA_SUPPLICANT_ERROR, 0);
} // 当前网络是否连接失败
public static boolean isCurrentNetworkConnectFailed(intent intent) {
return WifiManager.ERROR_AUTHENTICATING == getCurrentNetworkCode(intent);
}

6、WifiManager.CONFIGURED_NETWORKS_CHANGED_ACTION:

      官方的注释是这么说的, 广播已配置的网络发生变化, 可由添加, 修改, 删除网络的触发. 当从intent中取出key值为EXTRA_MULTIPLE_NETWORKS_CHANGED, 其值为true时, 那么字段EXTRA_WIFI_CONFIGURATION中取出来的配置已经过时, 不是最新配置了, 具体的代码为:

    // 是否多重网络发生变化.
public static boolean isMultipleNetworkChanged(Intent intent) {
return intent.getBooleanExtra(WifiManager.EXTRA_MULTIPLE_NETWORKS_CHANGED, false);
} // 获取当前最新网络配置:
public static WifiConfiguration getCurWifiConfig(Intent intent) {
return intent.getParcelableExtra(WifiManager.EXTRA_WIFI_CONFIGURATION);
}

7、WifiManager.LINK_CONFIGURATION_CHANGED_ACTION:

      WIFI连接配置发生改变的广播. 此时, 网路连接功能封装LinkProperties和NetworkCapabilities可能发生变化.

    // 获取 LinkProperties
public static LinkProperties getLinkProperties(Intent intent) {
return intent.getParcelableExtra(WifiManager.EXTRA_LINK_PROPERTIES);
} // 获取 NetworkCapabilities
public static NetworkCapabilities getNetworkCapabilities(Intent intent) {
return intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_CAPABILITIES);
}

8、WifiManager.NETWORK_STATE_CHANGED_ACTION:

      WIFI连接状态发生改变的广播. 可以从intent中取得NetworkInfo, 此时NetworkInfo中提供了连接的新状态, 如果连接成功, 可以获取当前连接网络的BSSID, 和WifiInfo. 相关代码:

    // 获取当前网络
public static NetworkInfo getCurrentNetworkInfo(Intent intent) {
return intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
} // 获取当前网路状态.
public static NetworkInfo.State getCurrentNetworkState(NetworkInfo info) {
return info != null ? info.getState() : null;
} // 获取当前网路BSSID.
public static String getCurrentNetworkBssid(Intent intent) {
return intent.getStringExtra(WifiManager.EXTRA_BSSID);
} // 获取当前网路的WifiInfo. wifi 连接成功有效.
public static WifiInfo getCurrentWifiInfo(Intent intent) {
return intent.getParcelableExtra(WifiManager.EXTRA_WIFI_INFO);
}

9、WifiManager.RSSI_CHANGED_ACTION:

      WIFI热点信号强度发生变化的广播. 可以获取当前变化热点的最新的信号强度.

    // 获取当前热点最新的信号强度
public static int getCurrentNetworkRssi(Intent intent) {
return intent.getIntExtra(WifiManager.EXTRA_NEW_RSSI, -1000);
}

二、Android即时网络监听——BroadcastReceiver

      通常我们在进行网络请求之前,会先进行网络状态判断,再决定是否进行网络请求,常用方法如下:

/**
* 判断网络是否可用
*
* @return true/false
*/
@SuppressLint("MissingPermission")
public static boolean isNetworkAvailable() {
ConnectivityManager connMgr = (ConnectivityManager) NetworkListener.getInstance().getContext().getSystemService(Context.CONNECTIVITY_SERVICE);
if (connMgr == null) {
return false;
}
NetworkInfo[] infos = connMgr.getAllNetworkInfo();
if (infos != null) {
for (NetworkInfo info : infos) {
if (info.getState() == NetworkInfo.State.CONNECTED) {
return true;
}
}
}
return false;
} /**
* 获取当前网络类型
*
* @return NetType
*/
@SuppressLint("MissingPermission")
public static NetType getNetType() {
ConnectivityManager connMgr = (ConnectivityManager) NetworkListener.getInstance().getContext().getSystemService(Context.CONNECTIVITY_SERVICE);
if (connMgr == null) {
return NetType.NONE;
}
NetworkInfo networkInfo = connMgr.getActiveNetworkInfo();
if (networkInfo == null) {
return NetType.NONE;
}
int nType = networkInfo.getType();
if (nType == ConnectivityManager.TYPE_MOBILE) {
if ("cmnet".equals(networkInfo.getExtraInfo().toLowerCase())) {
return NetType.CMNET;
} else {
return NetType.CMWAP;
}
} else if (nType == ConnectivityManager.TYPE_WIFI) {
return NetType.WIFI;
}
return NetType.NONE;
}

但这种做法无法做到即时网络监听,例如在播放视频或下载文件过程中,网络状态发生变化,我们无法做到即时处理,解决方式有2种:

      (1)使用广播方式

      (2)使用ConnectivityManager.NetworkCallback方式

      本次我们先使用广播监听的方式进行网络变化监听。

我们知道,网络状态发生变化的时候,系统会发出android.net.CONNECTIVITY_CHANGE广播,所以我们可以用监听此广播的方式来判断网络连接:

1、权限申请

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />

2、创建常量

//网络连接改变广播
public static final String ANDROID_NET_CHANGE_ACTION = "android.net.conn.CONNECTIVITY_CHANGE";

3、定义枚举类,表示网络状态:

public enum NetType {
//任意网络
AUTO,
//WIFI
WIFI,
CMNET,
//手机上网
CMWAP,
//无网络
NONE
}

4、定义网络监听接口:

public interface NetChangeListener {
/**
* 已连接
* @param netType NetType
*/
void onConnect(NetType netType); /**
* 连接断开
*/
void onDisConnect();
}

5、创建广播接收者:

public class NetworkStateReceiver extends BroadcastReceiver {
private static final String TAG = "NetworkStateReceiver";
private NetType netType;//网络类型
private NetChangeListener listener; public NetworkStateReceiver() {
//初始化网络连接状态
this.netType = NetType.NONE;
} public void setListener(NetChangeListener listener) {
this.listener = listener;
} @Override
public void onReceive(Context context, Intent intent) {
if (intent == null || intent.getAction() == null) {
Log.e(TAG, "onReceive: 异常");
return;
}
if (intent.getAction().equals(Constants.ANDROID_NET_CHANGE_ACTION)) {
Log.d(TAG, "onReceive: 网络发生变化");
//获取当前联网的网络类型
netType = NetworkUtils.getNetType();
if (NetworkUtils.isNetworkAvailable()) {
Log.d(TAG, "onReceive: 网络连接成功");
if (listener != null) {
listener.onConnect(netType);
}
} else {
Log.e(TAG, "onReceive: 网络连接失败");
if (listener != null) {
listener.onDisConnect();
}
}
}
}
}

6、定义NetworkListener类(单例)用于初始化监听:

public class NetworkListener {
private Context context;
private NetworkStateReceiver receiver; /**
* 私有化构造方法
*/
private NetworkListener() {
receiver = new NetworkStateReceiver();
} private static final SingletonTemplate<NetworkListener> INSTANCE = new SingletonTemplate<NetworkListener>() {
@Override
protected NetworkListener create() {
return new NetworkListener();
}
}; public static NetworkListener getInstance() {
return INSTANCE.get();
} public Context getContext() {
return context;
} public void setListener(NetChangeListener listener) {
receiver.setListener(listener);
} /**
* 初始化
*
* @param context context
*/
@SuppressLint("MissingPermission")
public void init(Context context) {
this.context = context;
IntentFilter filter = new IntentFilter();
filter.addAction(Constants.ANDROID_NET_CHANGE_ACTION);
context.registerReceiver(receiver, filter);
}
}

7、使用:

Application中初始化:

NetworkListener.getInstance().init(this);

在需要监听的Activity中实现NetChangeListener接口,并在onCreate()中初始化NetworkListener,如下:

public class MainActivity extends AppCompatActivity implements NetChangeListener {
private static final String TAG = "MainActivity"; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
NetworkListener.getInstance().setListener(this);
} @Override
public void onConnect(NetType netType) {
Log.d(TAG, "onConnect: 网络连接成功:状态_" + netType.name());
} @Override
public void onDisConnect() {
Log.e(TAG, "onDisConnect: 网络连接断开");
}
}

通过以上代码,我们可以实现在APP运行过程中实时监听网络连接状态,此方式使用广播监听结合接口回调实现。

三、Android即时网络监听——ConnectivityManager.NetworkCallback

1、新建NetworkCallbackImpl类继承ConnectivityManager.NetworkCallback,并重写onAvailable、onLost、onCapabilitiesChanged三个方法:

@Override
public void onAvailable(Network network) {
super.onAvailable(network);
Log.d(TAG, "onAvailable: 网络已连接");
} @Override
public void onLost(Network network) {
super.onLost(network);
Log.e(TAG, "onLost: 网络已断开");
} @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.d(TAG, "onCapabilitiesChanged: 网络类型为wifi");
post(NetType.WIFI);
} else if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
Log.d(TAG, "onCapabilitiesChanged: 蜂窝网络");
post(NetType.CMWAP);
} else {
Log.d(TAG, "onCapabilitiesChanged: 其他网络");
post(NetType.AUTO);
}
}
}

2、注册NetworkCallbackImpl:

NetworkCallbackImpl networkCallback = new NetworkCallbackImpl();
NetworkRequest.Builder builder = new NetworkRequest.Builder();
NetworkRequest request = builder.build();
ConnectivityManager connMgr = (ConnectivityManager) NetworkListener.getInstance().getContext().getSystemService(Context.CONNECTIVITY_SERVICE);
if (connMgr != null) {
connMgr.registerNetworkCallback(request, networkCallback);
}

做完以上两步之后,运行代码,不出意外的话,网络状态改变就可以正常检测出来了。

参考博客:

【1】Android WIFI开发之广播监听

【2】Android-WiFi开发之 WiFi广播监听(格式化版)

【3】Android即时网络监听(一)-BroadcastReceiver

【4】Android即时网络监听(二)-ConnectivityManager.NetworkCallback

【5】Android WiFi P2P开发实践笔记

Android实现网络监听的更多相关文章

  1. Android 手势水平监听判断

    package com.zihao.ui; import com.zihao.R; import android.os.Bundle; import android.app.Activity; imp ...

  2. Android中如何监听GPS开启和关闭

    转自 chenming 原文 Android中如何监听GPS开启和关闭   摘要: 本文简单总结了如何监听GPS开关的小技巧 有时需要监听GPS的开关(这种需求并不多见).实现的思路是监听代表 GPS ...

  3. Android手机上监听短信的两种方式

    Android手机上监听短信有两种方式: 1. 接受系统的短信广播,操作短信内容. 优点:操作方便,适合简单的短信应用. 缺点:来信会在状态栏显示通知信息. AndroidManifest.xml: ...

  4. iOS 网络监听、判断

    一 网络监听 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary ...

  5. 从零开始学 Web 之 HTML5(三)网络监听,全屏,文件读取,地理定位接口,应用程序缓存

    大家好,这里是「 从零开始学 Web 系列教程 」,并在下列地址同步更新...... github:https://github.com/Daotin/Web 微信公众号:Web前端之巅 博客园:ht ...

  6. android的电话监听

    android的电话监听 新建一个项目,结构图如下: PhoneService: package com.demo.tingdianhua; import android.app.Service; i ...

  7. iOS:Reachability网络监听

    iOS利用Reachability确认网络环境3G/WIFI 开发Web等网络应用程序的时候,需要确认网络环境,连接情况等信息.如果没有处理它们,是不会通过Apple的审查的,一般情况下,可以把网络监 ...

  8. java实现网络监听

    Java实现网络监听 import java.net.*; import java.io.*; public class tcpServer { public static void main(Str ...

  9. Android零基础入门第34节:Android中基于监听的事件处理

    原文:Android零基础入门第34节:Android中基于监听的事件处理 上一期我们学习了Android中的事件处理,也详细学习了Android中基于监听的事件处理,同时学会了匿名内部类形式,那么本 ...

随机推荐

  1. Nessus home版插件更新

    1,进入服务器停止服务 service nessusd stop 2,进入目录执行命令获取Challenge code cd /opt/nessus/sbin/ ./nessuscli fetch - ...

  2. pip切换源

    pip国内的一些镜像 阿里云http://mirrors.aliyun.com/pypi/simple/ 中国科技大学https://pypi.mirrors.ustc.edu.cn/simple/ ...

  3. ES6遍历对象方法

    ES6 一共有 5 种方法可以遍历对象的属性. (1)for...in for...in循环遍历对象自身的和继承的可枚举属性(不含 Symbol 属性). let obj = {a:1,b:2,c:3 ...

  4. js 实现匀速移动

    js 实现匀速移动 <!DOCTYPE html> <html lang="en"> <head> <meta charset=" ...

  5. Django笔记&教程 6-2 表单(Form)基础操作

    Django 自学笔记兼学习教程第6章第2节--表单(Form)基础操作 点击查看教程总目录 1 - 编写表单类 创建新的表单类的代码,一般写到一个专门的forms.py文件中(一般放在对应的app文 ...

  6. dos的基本命令

    打开cmd的方式 开始+系统+命令提示符 Win键+R 输入cmd打开控制台(推荐使用) 在任意的文件夹下面,按住shift键+鼠标右键点击,在此处打开命令行窗口 资源管理器的地址栏前面加上cmd + ...

  7. GO的安装以及GoLand破解

    GO的安装以及GoLand破解 GO的安装 GO语言中文网:GO语言中文网 go,GoLand,破解文件:JetBrains GoLand 2019.2.3 x64 提取码:ABCD(汉化文件也在其中 ...

  8. [cf1495D]BFS Trees

    记$d_{G}(x,y)$表示无向图$G$中从$x$到$y$的最短路,设给定的图为$G=(V,E)$,$T$为其生成树,$E_{T}$为$T$的边集 下面,考虑计算$f(x,y)$-- 首先,对于一棵 ...

  9. cube+FreeRTOS联合开发采坑笔记

    加了看门狗之后不断重启的可能 原因: 任务容量分配不足,在"FreeRTOSConfig.h"的配置中,有个configTOTAL_HEAP_SIZE中将堆大小调到最大.

  10. Electron快速入门

    node -v npm -v 安装node环境 my-electron-app/ ├── package.json ├── main.js └── index.html 为您的项目创建一个文件夹并安装 ...