由於本人並沒有對於android的app編寫熟悉,因此通過自學簡單的實現了一個android下的RSSI和Magnetic採集工具。
使用Android Studio進行開發。創建一個android app。
第一步,添加我們在android程序中需要用到的外部庫(權限申請我們使用的是easypermissions,ble庫我們用的是FastBle)
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation 'com.android.support:appcompat-v7:28.0.0'
implementation 'com.android.support.constraint:constraint-layout:1.1.3'
implementation 'com.android.support:design:28.0.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
implementation 'pub.devrel:easypermissions:2.0.0'
implementation files('libs/FastBLE-2.3.2.jar')
}
第二步,添加權限獲取
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.INTERNET"/>
<!--以下權限需要動態申請-->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme"
tools:ignore="AllowBackup,GoogleAppIndexingWarning">
<activity
android:name=".dc_MainActivity"
android:label="@string/app_name"
android:theme="@style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".dc_CollectActivity"
android:label="@string/app_name">
</activity>
</application>
第三步,創建模板:
模板類繼承AppCompatActivity,並且實現接口中定義的所有抽象方法(EasyPermissions.PermissionCallbacks,View.OnClickListener)
public class dc_MainActivity extends AppCompatActivity implements EasyPermissions.PermissionCallbacks,View.OnClickListener{
}
實現動態權限代碼:
//把申請權限的回調交由EasyPermissions處理
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this);
}
//授權成功
@Override
public void onPermissionsGranted(int requestCode, @NonNull List<String> perms) {
}
//授權失敗
@Override
public void onPermissionsDenied(int requestCode, @NonNull List<String> perms) {
if (EasyPermissions.somePermissionPermanentlyDenied(this, perms)) {
new AppSettingsDialog.Builder(this).build().show();
}
}
打開BLE和定位GPS權限:
//初始化權限
private void initPermissions() {
openBlueSwitch();
openGPSLocation();
String[] permissions = {
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
};
if (EasyPermissions.hasPermissions(this, permissions)) {
Toast.makeText(this, R.string.permissionsOk, Toast.LENGTH_LONG).show();
} else {
EasyPermissions.requestPermissions(this, "需要定位和讀寫權限", REQUEST_CODE, permissions);
}
}
private void openBlueSwitch(){
BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (!bluetoothAdapter.isEnabled()) {
new AlertDialog.Builder(this)
.setTitle(R.string.notifyTitle)
.setMessage(R.string.please_open_blue)
.setNegativeButton(R.string.cancel,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
finish();
}
})
.setPositiveButton(R.string.setting,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Intent intent = new Intent(Settings.ACTION_BLUETOOTH_SETTINGS);
startActivityForResult(intent, 1);
}
})
.setCancelable(false)
.show();
}
}
private void openGPSLocation(){
LocationManager locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
if(!locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)){
new AlertDialog.Builder(this)
.setTitle(R.string.notifyTitle)
.setMessage(R.string.gpsNotifyMsg)
.setNegativeButton(R.string.cancel,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
finish();
}
})
.setPositiveButton(R.string.setting,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
startActivityForResult(intent, 1);
}
})
.setCancelable(false)
.show();
}
}
第四步:藍牙RSSI搜索使用fastBle包進行開發
設置BLE搜索config:
private void setScanRule() {
BleScanRuleConfig scanRuleConfig = new BleScanRuleConfig.Builder()
.setDeviceName(true, "HengDa_dmd_iBeacon")
.setScanTimeOut(1000)
.build();
BleManager.getInstance().initScanRule(scanRuleConfig);
}
開始搜索:
private void startScanning() {
BleManager.getInstance().enableBluetooth();
BleManager.getInstance().scan(new BleScanCallback() {
@Override
public void onScanStarted(boolean success) {
mDeviceAdapter.clearScanDevice();
mDeviceAdapter.notifyDataSetChanged();
}
@Override
public void onScanFinished(List<BleDevice> scanResultList) {
ArrayList<String> rssiList = new ArrayList<>();
for (int i = 0; i < scanResultList.size(); i++) {
BleDevice device = scanResultList.get(i);
rssiList.add("(device:" + device.getDevice() +
" rssi:" + Integer.toString(device.getRssi()) +
// " " + mDeviceAdapter.getMagnetic_x() +
// " " + mDeviceAdapter.getMagnetic_y() +
// " " + mDeviceAdapter.getMagnetic_z() +
" floorNum:" + editFloorNum.getText() +
" locationNum:" + editLocationNum.getText() + ")");
}
if(STATUSFLAG == 1){
startScanning();
mAsynDataSave.DataSave(String.valueOf(rssiList));
}else if(STATUSFLAG == 0){
BleManager.getInstance().cancelScan();
}
}
@Override
public void onLeScan(BleDevice bleDevice) {
super.onLeScan(bleDevice);
}
@Override
public void onScanning(BleDevice bleDevice) {
mDeviceAdapter.addDevice(bleDevice);
mDeviceAdapter.notifyDataSetChanged();
}
});
}
在上述代碼中,我們可以觀察到這樣一行代碼:
mAsynDataSave.DataSave(String.valueOf(rssiList));
這樣做的原因是由於我們需要將收集到的數據進行收集寫入文本文件中(暫時沒有考慮使用數據庫進行數據存儲,由於開發時間問題,隨後將以實現)
寫入文件我們沒法在主線程中來實現,由於寫SD卡文件需要一定的時間,放在主線程中會導致數據的寫入讀取丟失。
第五步:異步文件讀
創建一個可以進行休眠的常開線程
private final Object lock = new Object();
private ConcurrentLinkedQueue<String> mQueue = new ConcurrentLinkedQueue<String>();
void DataSave(String str){
dc_AsyncDataSave.getInstance().Log(str);
}
void enqueue(String str) {
mQueue.add(str);
if(!isRunning){
synchronized (lock){
lock.notify();
}
}
}
public void run() {
while(true) {
synchronized(lock) {
isRunning = true;
while (!mQueue.isEmpty()) {
try {
recordStr2Txt(mQueue.poll());
} catch (Exception e) {
e.printStackTrace();
}
}
isRunning = false;
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
通過上面的代碼,我們可以在添加另外的邏輯和UI操作來完成android app。之後使用android手機對RSSI和magnetic進行採集。
app界面:
在這個app中,我們採集到的數據用來對於模型的訓練,其中我們在某個點,輸入該點的floor和location值,之後採集該地的RSSI和magnetic信息,存儲在txt中,之後,我們將對txt中的數據進行分析處理建模
歡迎大家批評!!!