WiFi的搜索
我们在开始搜索WiFi之前确保当前WiFi功能是处于开启状态。如果未开启,通过调用WifiManager的setWifiEnabled(boolean enable)去开启。之后调用startScan()就开始扫描附近的WiFi了。而获取扫描的结果我们就需要创建一个广播接收者来处理。
private BroadcastReceiver receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) { final String action = intent.getAction(); if (action.equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) {
系统在扫描结束后,会发出WifiManager.SCAN_RESULTS_AVAILABLE_ACTION的广播,当我们的接收者接收到这个广播的时候,通过WifiManager的getScanResults()就能获取到扫描结果的集合了。ScanResult保存着每一个WiFi的信息。这里我将这个集合设置到Adapter中,并在列表中展示出来。下面是Apater中主要的代码:
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) { convertView = mInflater.inflate(mResource, parent, false); } TextView name = (TextView) convertView.findViewById(R.id.wifi_name); TextView signl = (TextView) convertView.findViewById(R.id.wifi_signal); ScanResult scanResult = getItem(position); name.setText(scanResult.SSID); int level = scanResult.level; if (level <= 0 && level >= -50) { signl.setText("信号很好"); } else if (level < -50 && level >= -70) { signl.setText("信号较好"); } else if (level < -70 && level >= -80) { signl.setText("信号一般"); } else if (level < -80 && level >= -100) { signl.setText("信号较差"); } else { signl.setText("信号很差"); } return convertView; }
可以看出列表展示的数据也是比较简单,只有WiFi的名称和信号强度,这两个数据也是平时用得比较多的。获取到扫描结果后,我们就可以处理连接的逻辑了。
WiFi的连接
WiFi的连接相当于搜索就要复杂一些。首先给列表项设置点击事件,获取对应的ScanResult。
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
wifiManager.disconnect();
final ScanResult scanResult = wifiListAdapter.getItem(position);
String capabilities = scanResult.capabilities;
int type = WIFICIPHER_WPA; if (!TextUtils.isEmpty(capabilities)) { if (capabilities.contains("WPA") || capabilities.contains("wpa")) { type = WIFICIPHER_WPA; } else if (capabilities.contains("WEP") || capabilities.contains("wep")) { type = WIFICIPHER_WEP; } else { type = WIFICIPHER_NOPASS; } } config = isExsits(scanResult.SSID); });
获取到ScanResult后我们通过他的capabilities属性判断WiFi的加密方式。接着通过isExsits(String SSID)方法判断系统是否保存着当前WiFi的信息。
private WifiConfiguration isExsits(String SSID) {
List<WifiConfiguration> existingConfigs = wifiManager.getConfiguredNetworks();
for (WifiConfiguration existingConfig : existingConfigs) {
if (existingConfig.SSID.equals("\"" + SSID + "\"")) { return existingConfig; } } return null; }
如果之前连接过,则返回WiFi的配置信息,否则返回空对象。然后接着处理连接的逻辑
if (config == null) {
if (type != WIFICIPHER_NOPASS) {
当没有获取到所要连接WiFi的配置信息时,我们就需要用到前面获取到的加密方式判断是否需要输入密码。如果加密方式为WAP或WEP时,则弹出提示框提示用户输入WiFi密码。用户输入密码后再调用connect(WifiConfiguration config)方法
如果可以获取到所要连接WiFi的配置信息,则直接调用connect(WifiConfiguration config)。
private void connect(WifiConfiguration config) {
int wcgID = wifiManager.addNetwork(config);
wifiManager.enableNetwork(wcgID, true); }
直接调用WifiManger的addNetwork方法,将配置信息传进去后,会创建一个新的网络描述的身份并返回回来,如果返回来是-1,则表示创建失败。获取到身份后,调用enableNetwork方法就能开始连接WiFi了。到了这里,我们连接部分就完成了一半,接下来需要继续处理WiFi连接过程中返回来的状态。这里同样我们是需要用到广播接收者来处理。
if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
NetworkInfo info = intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO)
上面是广播接收者中的关键代码。WiFi在连接的过程中系统会发出WifiManager.NETWORK_STATE_CHANGED_ACTION的广播,当接收者接收到这条广播时,获取NetworkInfo的state来判断当前的连接状态。状态值分别代表如下
NetworkInfo.State.DISCONNECTED //连接已断开
NetworkInfo.State.CONNECTED //已成功连接
除了这两个状态之外,这里还判断了其他状态
NetworkInfo.DetailedState state = info.getDetailedState();
if (state == state.CONNECTING) {
text_state.setText("连接中..."); } else if (state == state.AUTHENTICATING) { text_state.setText("正在验证身份信息..."); } else if (state == state.OBTAINING_IPADDR) { text_state.setText("正在获取IP地址..."); } else if (state == state.FAILED) { text_state.setText("连接失败"); }
DetailedState中包含了很多连接状态的信息,这里只对部分状态进行处理,其他状态值解析具体如下
IDLE:空闲
SCANNING:正在扫描
CONNECTING:连接中
AUTHENTICATING:正在进行身份验证
OBTAINING_IPADDR:正在获取Ip地址
CONNECTED:已连接
SUSPENDED:已暂停
DISCONNECTING:正在断开连接
DISCONNECTED:已断开
FAILED:失败
BLOCKED:已阻止
VERIFYING_POOR_LINK:暂时关闭(网络状况不佳)
CAPTIVE_PORTAL_CHECK:判断是否需要浏览器二次登录