Android环境下WiFi信号采集器的设计

1.开发意图

由于最近要进行室内定位的实习,需要采集室内的WiFi信息来进行定位。需要采集的WiFi信息有WiFi名称(SSID)、WiFi信号的Mac地址(BSSID)、WiFi的频率(frequency)和WiFi的信号强度(level)。由于网上的大多是给出用于连接的软件,也就是说并没有注意WiFi的Mac地址和定量的信号强度。而且还有很多不能导出为txt文件,这些缺点对于后期的室内定位数据处理来说是很麻烦的。因此打算自己去利用Android Studio写一个专门用于采集WiFi信号的APP。界面不是很美丽,也暂时只能采集WiFi信号强度和将采集到的文件导出为txt文本,后续会加上采集蓝牙信号强度的代码。

2.采用的主要的类

wifiManager = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE);

Android SDK中自带有能够调用设备本身的WiFi信号处理器的类,也就是WifiManager类。

List<ScanResult> WifiList;
wifiManager.startScan();
WifiList = wifiManager.getScanResults();//返回的是用于存储WiFi信息的列表

上面的代码片就是如何获取设备感知到的WiFi信息。ScanResult也是一个类,用来储存得到的WiFi信号的基本信息。其中我们想要的就是SSID,BSSID,frequency,level。在得到列表之后,遍历列表就可以得到WiFi的信息。这个类是不要求与手机与WiFi相连接的,在室内定位建立指纹库的过程中,总不能挨个去连接WiFi。而是要每次自动扫描出附近的WiFi信号。把上述的结果放入一个字符串中,后续要将这个字符串写入文件中。代码如下:

ScanResult scanResult;
for (int i = 0; i < WifiList.size(); i++) {
    scanResult = WifiList.get(i);
    stringBuffer
            .append(scanResult.SSID).append("   ")
            .append(scanResult.BSSID).append("    ")
            .append(scanResult.frequency).append("  ")
            .append(scanResult.level).append("\n");
}

如果想要采集某一时刻的WiFi信息,上面的代码足够了,但是由于室内定位的建库阶段需要在一个时间段内不断地进行WiFi信息的搜集,因此还需要设置实时更新一下。网上有好多关于每隔一定的时间间隔采集一次数据的教程,但是我用的应该是最笨的一种方法。也就是说设计了一个计时器,然后为计时器的时间更新监听器绑定一个扫描时间,这样就可以达到一秒一次的采集效果。
下面就应该是文件的读写了。
在Android平台上文件的读写本质上就是利用了Java的IO流进行,当然也有Android的创新的地方。创新的地方就是引入了openFileOutput和openFileInput两个函数用来读写内部存储的数据。说到这里,还得插一嘴什么是内部存储和外部存储。不管在日常的生活中如何称呼外存和内存,在Android开发过程中,将应用自带的文件成为内存,将自己手机有的文件成为外存。也就是说内存中的一切东西都会随着APP的卸载被删除,随着APP的安装被写入。在手机内是无法直接看到APP内部自带的数据的,也就是无法直接看到内存。而我们的手机能够看到的是外存,也就是在SD卡中的东西。不过现在的大多数手机都没有SD卡。但是这并不妨碍手机拥有外存。没有外存的手机的获取外部存储路径得到的路径大多是手机的/storage/emulated/0这个目录下。

state = Environment.getExternalStorageState();
if (state.equals(Environment.MEDIA_MOUNTED)) {
    //path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS);
    path=Environment.getExternalStorageDirectory().getAbsolutePath();
}

上面的代码是用来获取手机的外部存储的绝对路径,返回的path是一个String,再利用下面的代码在该路径中创建相应的文本文件来存储获得的WiFi信息。

File file = new File(path,"wifi0.txt");
try{
    file.createNewFile();
}catch (IOException e){
    e.printStackTrace();
}

最后再将上面的WiFi信息利用FileOutputStream来写入文件中就可以了。

3.遇到的问题

虽然流程只有那么简单,但是由于我是刚刚入门的,所以在实际的开发过程中还是有不少问题的。下面就一一列举我的问题,记录下来防止下次写的时候忘记了。

(1)动态申请权限的问题

由于在WiFi信号采集的时候需要用到位置服务和读写外部存储的危险权限,因此需要动态申请权限。首先要在AndroidManefest.xml中添加如下代码

<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

然后需要在MainActivity.java文件中添加如下代码

String[] permissions=new String[]{Manifest.permission.ACCESS_COARSE_LOCATION,Manifest.permission.WRITE_EXTERNAL_STORAGE};//用于存储需要申请的危险权限
List<String> mPermissions=new ArrayList<>();//用于存储未申请的危险权限
//下面的函数用于动态申请危险权限,需要在主函数中调用initPermission函数才能申请动态权限
private  void initPermission(){
    mPermissions.clear();

    for(int i=0;i<permissions.length;i++){
        if(ContextCompat.checkSelfPermission(this,permissions[i])!=PackageManager.PERMISSION_GRANTED)
            mPermissions.add(permissions[i]);
    }

    if(mPermissions.size()>0){
        ActivityCompat.requestPermissions(this,permissions,1);
    }
}

注意一定要按照上面的方法动态申请权限,否则在首次安装应用的时候并不会弹出请求位置服务和读写存储的对话框。切记切记!!!!因为我就在这个地方卡住了好几天。我最开始的时候是按照下面的方式动态申请权限的

/*if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
    if(ActivityCompat.shouldShowRequestPermissionRationale(this,Manifest.permission.WRITE_EXTERNAL_STORAGE)){}
    else{
        ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
    }
}

if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
    if(ActivityCompat.shouldShowRequestPermissionRationale(this,Manifest.permission.ACCESS_COARSE_LOCATION)){}
    else {
        ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, 1);
    }
}*/

因为我看到申请一个权限可以这样申请,所以就类推了一下,以为申请多个权限也可以这样申请。结果废了好长时间…上面那样申请的结果就是不会弹出对话框,至于为什么这样,我也不知道。学艺不精…

(2)组件初始化的问题

图形界面
上面的图片是我的页面布局。开始的时候我在下面用到了判断这几个按钮的文本是否等于一个字符串的判断语句,而且我只在布局文件中定义了按钮的text,并没有在函数中进行初始化,也就是说没有在主函数中使用setText操作。这样做会使我的按钮点击两次才反应过来,也就说第一次点击才进行初始化,第二次点击才执行事件。这个也花了好长时间才改过来。

(3)文件存储位置的问题

我的手机是OPPO R11splus,在调试的时候显示文件的存储路径还是/storage/emulated/0,这就要了我这个不懂手机的人的命了。。。后来用室友(狐朋狗友,哈哈哈)的华为手机发现文件并没有存在相应的文件夹中,而是直接存在了“手机存储/”这个文件夹下,然后又用了另外一个室友的小米手机,发现存在了/storage/emulated/0这个目录下。然后我再反过来看我的手机,发现我的手机也是存在了“手机存储/”目录下。我不明白这个里面的原理,但是在调试的时候确实是显示在/storage/emulated/0目录下的,而且我判断文件是存在的,就是结果莫名其妙地出现在了另外一个目录下。哎,还是学艺不精啊。。。要是有大佬知道这个里面的原理,还请多多指教呀!

总结

这次的开发让我知道了,果然代码都是相通的。上次我问老师这个代码对我们专业来说究竟掌握到什么程度才算合适呢,老师说看个人经历吧。我以前总感觉自己太过于深究代码为什么这样编写,自己的专业并不需要这样,这是计算机学院的学生应该做的。但是通过这次的APP开发我知道了,如果平时不深究代码,不掌握基本的语法,到关键的时候就看不懂别人的东西,只能拿来别人的东西一个一个试,耗时又耗力,还不如平时多深究一点(例如我上面的动态权限申请就偷懒了,一偷懒就出错啊)。而且看不下去代码,更别提自己写了。任何的代码写上两万行都会掌握的。还是多写多练吧。加油!!!!
后续我会把蓝牙的代码也写了,看看有没有什么大坑等着我跳。

  • 1
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值