在上一篇中我们介绍了WiFi热点的创建和关闭,如果你还没阅读过,建议先阅读上一篇文章Android WiFi开发教程(一)——WiFi热点的创建与关闭。 本章节主要继续介绍WiFi的搜索和连接。

WiFi的搜索

  /* 搜索wifi热点
*/
private void search() {
if (!wifiManager.isWifiEnabled()) {
//开启wifi
wifiManager.setWifiEnabled(true);
}
wifiManager.startScan();
}

我们在开始搜索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)) {
// wifi已成功扫描到可用wifi。
List<ScanResult> scanResults = wifiManager.getScanResults();
wifiListAdapter.clear();
wifiListAdapter.addAll(scanResults);
}
};

系统在扫描结束后,会发出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) {//需要密码
final EditText editText = new EditText(MainActivity.this);
final int finalType = type;
new AlertDialog.Builder(MainActivity.this).setTitle("请输入Wifi密码").setIcon(
android.R.drawable.ic_dialog_info).setView(
editText).setPositiveButton("确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Log.w("AAA", "editText.getText():" + editText.getText());
config = createWifiInfo(scanResult.SSID, editText.getText().toString(), finalType);
connect(config);
}
})
.setNegativeButton("取消", null).show();
return;
} else {
config = createWifiInfo(scanResult.SSID, "", type);
connect(config);
}
} else {
connect(config);
}

当没有获取到所要连接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); if (info.getState().equals(NetworkInfo.State.DISCONNECTED)) {
text_state.setText("连接已断开");
} else if (info.getState().equals(NetworkInfo.State.CONNECTED)) {
WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
final WifiInfo wifiInfo = wifiManager.getConnectionInfo();
text_state.setText("已连接到网络:" + wifiInfo.getSSID()); }
} else {
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("连接失败");
}
} }

上面是广播接收者中的关键代码。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:判断是否需要浏览器二次登录

到这里WiFi连接的逻辑就处理完成了,相对于WiFi热点的创建和关闭,搜索和连接确实要复杂一些。欢迎阅读下一篇Android WiFi开发教程(三)——WiFi热点数据传输

Android WiFi开发教程(二)——WiFi的搜索和连接的更多相关文章

  1. Android WiFi开发教程(一)——WiFi热点的创建与关闭

    相对于BlueTooth,WiFi是当今使用最广的一种无线网络传输技术, 几乎所有智能手机.平板电脑和笔记本电脑都支持Wi-Fi上网.因此,掌握基本的WiFI开发技术是非常必要的.本教程将围绕一个小D ...

  2. Android WiFi开发教程(三)——WiFi热点数据传输

    在上一篇文章中介绍了WiFi的搜索和连接,如果你还没阅读过,建议先阅读上一篇Android WiFi开发教程(二)——WiFi的搜索和连接.本篇接着简单介绍手机上如何通过WiFi热点进行数据传输. 跟 ...

  3. Android蓝牙开发教程(三)——蓝牙设备相互通讯

    在上一篇中已经介绍如何连接我们搜索到的蓝牙设备,如果你还没阅读过,建议先看看上一篇文章Android蓝牙开发教程(二)——连接蓝牙设备 在上一篇文章中,无论是自动连接还是被动连接,连接成功后,都是将获 ...

  4. Android Studio系列教程二--基本设置与运行

    Android Studio系列教程二--基本设置与运行 2014 年 11 月 28 日 DevTools 本文为个人原创,欢迎转载,但请务必在明显位置注明出处! 上面一篇博客,介绍了Studio的 ...

  5. Android高手进阶教程(二十八)之---Android ViewPager控件的使用(基于ViewPager的横向相册)!!!

      分类: Android高手进阶 Android基础教程 2012-09-14 18:10 29759人阅读 评论(35) 收藏 举报 android相册layoutobjectclassloade ...

  6. Android ADB命令教程二——ADB命令详解

    Android ADB命令教程二——ADB命令详解 转载▼ 原文链接:http://www.tbk.ren/article/249.html       我们使用 adb -h 来看看,adb命令里面 ...

  7. Android NFC开发(二)——Android世界里的NFC所具备的条件以及使用方法

    Android NFC开发(二)--Android世界里的NFC所具备的条件以及使用方法 NFC的应用比较广泛,而且知识面也是比较广的,所以就多啰嗦了几句,我还还是得跟着官方文档:http://dev ...

  8. Android ROM开发(二)——ROM架构以及Updater-Script脚本分析,常见的Status错误解决办法

    Android ROM开发(二)--ROM架构以及Updater-Script脚本分析,常见的Status错误解决办法 怪自己二了,写好的不小心弄没了,现在只好重新写一些了,上篇简单的配置了一下环境, ...

  9. MIP开发教程(二) 使用MIP-CLI工具调试MIP网页

    初始化 MIP 配置 新建一个 MIP 网页 编写 MIP 网页代码 校验 MIP 网页 调试 MIP 网页 1. 初始化 MIP 配置 首先在html目录下进行初始化 MIP 配置: $ mip i ...

随机推荐

  1. Server Tomcat v8.0 Server at localhost failed to start 问题解决方法?

    bi编程jsp  servlet 第一个程序: HelloServlet 运行错误 404: 十月 28, 2017 11:25:14 上午 org.apache.tomcat.util.digest ...

  2. JS——sort

    1.a-b升序 <script> var arr = [2, 3, 1, 5, 0]; function compare(a, b) { return a - b; } console.l ...

  3. postfix 邮件中继配置

    Postfix 配置邮件中继 A 邮件发送服务器B 邮件中继服务器 A. 配置发件服务器 # 开启转发规则 [root@Postfix ~]# vi /etc/postfix/main.cf tran ...

  4. STL_优先队列_(转载)

    转自:http://www.cnblogs.com/summerRQ/articles/2470130.html STL容器之优先队列 优先级队列,以前刷题的时候用的比较熟,现在竟然我只能记得它的关键 ...

  5. 不用float也可以让div横向显示

    display: inline-block; vertical-align: top; 就这两个属性,给div设置上,div就不会换行显示啦,而且还不影响横向的其他元素的显示.

  6. requirejs(模块化)

    <script src="../../dist/js/require.js" data-main="../../dist/js/main.js">& ...

  7. 【转】IDEA 中tomcat图片储存和访问虚拟路径

    1.idea 修改Tomcat的虚拟路径(第一种方法)修改配置文件有很多种,但是一直不成功;后来想还是idea的配置原因,这里tomcat虚拟路径只说一种; 修改Tomcat安装路径下server.x ...

  8. 在vue中通过js动态控制图片按比列缩放

    1.html 通过外层的div来给img对应的class,隐藏的img是得到img图片请求回来时的原始尺寸.外层div是固定大小,因此,图片有两种情况去适应外部div的尺寸.一种是宽度大于高度的情况, ...

  9. servlet之@PostConstruct,@PreDestroy

    1.@PostConstruct说明 被@PostConstruct修饰的方法会在服务器加载Servlet的时候运行,并且只会被服务器调用一次,类似于Serclet的inti()方法.被@PostCo ...

  10. flask之配置文件的加载和动态url的使用

    七行代码实现一个flask app from flask import Flask app = Flask(__name__) @app.route('/') def helloworld(): re ...