Android|安卓精准计步器并通过蓝牙实现对战PK功能
Posted JiangGH
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android|安卓精准计步器并通过蓝牙实现对战PK功能相关的知识,希望对你有一定的参考价值。
计步器功能实现
本章节功能实现参考:http://blog.csdn.net/linglongxin24/article/details/52868803
记步算法参考
添加权限
1 <!--计歩需要的权限--> 2 <uses-permission android:name="android.permission.VIBRATE" /> 3 <uses-permission android:name="android.permission.WRITE_SETTINGS" /> 4 <uses-feature android:name="android.hardware.sensor.accelerometer" /> 5 <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> 6 <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" /> 7 <uses-feature 8 android:name="android.hardware.sensor.stepcounter" 9 android:required="true" /> 10 <uses-feature 11 android:name="android.hardware.sensor.stepdetector" 12 android:required="true" />
检测手机是否支持记步
/** * 判断该设备是否支持计歩 * * @param context * @return */ @TargetApi(Build.VERSION_CODES.KITKAT) public static boolean isSupportStepCountSensor(Context context) { // 获取传感器管理器的实例 SensorManager sensorManager = (SensorManager) context .getSystemService(context.SENSOR_SERVICE); Sensor countSensor = sensorManager.getDefaultSensor(Sensor.TYPE_STEP_COUNTER); Sensor detectorSensor = sensorManager.getDefaultSensor(Sensor.TYPE_STEP_DETECTOR); return countSensor != null || detectorSensor != null; }
功能使用
1 private boolean isBind = false; 2 private Messenger mGetReplyMessenger = new Messenger(new Handler(this)); 3 private Messenger messenger; 4 5 /** 6 * 开启计步服务 7 */ 8 private void setupService() { 9 Intent intent = new Intent(this, StepService.class); 10 isBind = bindService(intent, conn, Context.BIND_AUTO_CREATE); 11 startService(intent); 12 13 14 } 15 /** 16 * 从service服务中拿到步数 17 * 18 * @param msg 19 * @return 20 */ 21 @Override 22 public boolean handleMessage(Message msg) { 23 switch (msg.what) { 24 case Constant.MSG_FROM_SERVER: 25 cc.setCurrentCount(10000, msg.getData().getInt("step")); 26 break; 27 } 28 return false; 29 } 30 31 32 /** 33 * 用于查询应用服务(application Service)的状态的一种interface, 34 * 更详细的信息可以参考Service 和 context.bindService()中的描述, 35 * 和许多来自系统的回调方式一样,ServiceConnection的方法都是进程的主线程中调用的。 36 */ 37 ServiceConnection conn = new ServiceConnection() { 38 /** 39 * 在建立起于Service的连接时会调用该方法,目前Android是通过IBind机制实现与服务的连接。 40 * @param name 实际所连接到的Service组件名称 41 * @param service 服务的通信信道的IBind,可以通过Service访问对应服务 42 */ 43 @Override 44 public void onServiceConnected(ComponentName name, IBinder service) { 45 try { 46 messenger = new Messenger(service); 47 Message msg = Message.obtain(null, Constant.MSG_FROM_CLIENT); 48 msg.replyTo = mGetReplyMessenger; 49 messenger.send(msg); 50 } catch (RemoteException e) { 51 e.printStackTrace(); 52 } 53 } 54 55 /** 56 * 当与Service之间的连接丢失的时候会调用该方法, 57 * 这种情况经常发生在Service所在的进程崩溃或者被Kill的时候调用, 58 * 此方法不会移除与Service的连接,当服务重新启动的时候仍然会调用 onServiceConnected()。 59 * @param name 丢失连接的组件名称 60 */ 61 @Override 62 public void onServiceDisconnected(ComponentName name) { 63 64 } 65 };
效果展示
GPS定位的实现
添加权限
<!-- 连接互联网Internet权限 --> <uses-permission android:name="android.permission.INTERNET" /> <!-- GPS定位权限 --> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <!-- 这个权限用于进行网络定位 --> <permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <!-- 这个权限用于访问GPS定位 --> <permission android:name="android.permission.ACCESS_FINE_LOCATION" />
实现定位服务
private void getLocation() { info_latitude = (TextView) findViewById(R.id.gps_latitude); info_longitude = (TextView) findViewById(R.id.gps_longitude); locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE); if (locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) { // 如果gps打开 getLocationInfo(); } else { // 如果没有打开gps toggleGPS(); new Handler() { }.postDelayed(new Runnable() { @Override public void run() { getLocationInfo(); } }, 2000); } }
调用系统设置打开GPS
private void toggleGPS() { Intent gpsIntent = new Intent(); gpsIntent.setClassName("com.android.settings", "com.android.settings.widget.SettingsAppWidgetProvider"); gpsIntent.addCategory("android.intent.category.ALTERNATIVE"); gpsIntent.setData(Uri.parse("custom:3")); try { PendingIntent.getBroadcast(this, 0, gpsIntent, 0).send(); } catch (PendingIntent.CanceledException e) { e.printStackTrace(); try { locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 1000, 0, locationListener); Location location1 = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER); if(location1 != null) { latitude = location1.getLatitude(); longitude = location1.getLongitude(); } } catch (SecurityException e1) { e1.printStackTrace(); info_latitude.setText("纬度获取异常"); info_longitude.setText("经度获取异常"); } } }
监听位置变化并显示经纬度信息
private void getLocationInfo() { try { Location location = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER); if (location != null) { latitude = location.getLatitude(); longitude = location.getLongitude(); } else { locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000, 0, locationListener); } if (latitude == 0.0 && longitude == 0.0) { info_longitude.setText("经纬度获取异常,请退出后重进,"); info_latitude.setText("并且确保位置服务开启!"); } else { info_latitude.setText("纬度:" + latitude); info_longitude.setText("经度:" + longitude); } } catch (SecurityException e) { e.printStackTrace(); info_latitude.setText("纬度获取异常"); info_longitude.setText("经度获取异常"); } } // 监听位置变化 LocationListener locationListener = new LocationListener() { // 当坐标改变时触发此函数,如果Provider传进相同的坐标,它就不会被触发 @Override public void onLocationChanged(Location location) { if (location != null) { latitude = location.getLatitude(); // 经度 longitude = location.getLongitude(); // 纬度 } } // provider的状态在可用、暂时不可用和无服务三个状态下直接切换时触发这个函数 @Override public void onStatusChanged(String s, int i, Bundle bundle) { } // provider被enable时触发这个函数,比如GPS被打开 @Override public void onProviderEnabled(String s) { } // Provider被disable时触发此函数,比如GPS被关闭 @Override public void onProviderDisabled(String s) { } };
蓝牙对战PK功能实现
添加权限
<uses-permission android:name="android.permission.BLUETOOTH"/> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/> <uses-feature android:name="android.hardware.bluetooth_le" android:required="true" />
初始化蓝牙服务
// 在APP启动时检查蓝牙状态 @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2) private void initBle() { bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE); bluetoothAdapter = bluetoothManager.getAdapter(); if (bluetoothAdapter == null) { Toast.makeText(this, "本设备不支持蓝牙!", Toast.LENGTH_LONG).show(); return; } // 如果没有打开蓝牙 if (!bluetoothAdapter.isEnabled()) { Toast.makeText(this,"本APP需要蓝牙服务,请打开蓝牙!",Toast.LENGTH_LONG).show(); Intent enableBleIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); startActivityForResult(enableBleIntent,REQUEST_ENABLE_BT); } // 如果蓝牙打开,进行广播注册 if (bluetoothAdapter.isEnabled()) { // 蓝牙广播注册 registerBluetooth(); } }
蓝牙广播注册
private IntentFilter intentFilter; void registerBluetooth() { intentFilter = makeFilter(); registerReceiver(bluetoothReceiver,intentFilter); } // 注册蓝牙广播,当扫描到设备时方便做处理 /** * 蓝牙广播过滤器 * 蓝牙状态改变 * 找到设备 * 扫描完成 * 开始扫描 * 状态改变 * */ public IntentFilter makeFilter() { IntentFilter filter = new IntentFilter(); filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);//蓝牙状态改变的广播 filter.addAction(BluetoothDevice.ACTION_FOUND);//找到设备的广播 filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);//搜索完成的广播 filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED);//开始扫描的广播 filter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);//状态改变 filter.addAction(BluetoothDevice.ACTION_FOUND); //搜索蓝压设备,每搜到一个设备发送一条广播 filter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED); //配对开始时,配对成功时 filter.addAction(BluetoothDevice.ACTION_ACL_CONNECTED); //配对时,发起连接 filter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECT_REQUESTED); filter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED); //配对结束时,断开连接 filter.addAction(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED); filter.addAction(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED);//更改蓝牙名称,打开蓝牙时,可能会调用多次 filter.addAction(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE); filter.addAction(BluetoothAdapter.ACTION_REQUEST_ENABLE); filter.addAction(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED);//搜索模式改变 return filter; }
蓝牙搜索回调
// 蓝牙开始搜索的回调 private BroadcastReceiver bluetoothReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); final BluetoothDevice device; if (action.equals(BluetoothDevice.ACTION_FOUND)) { device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); String bleMessage = device.getName() + ">>" + device.getAddress(); // 已匹配的设备 if (device.getBondState() == BluetoothDevice.BOND_BONDED) { // 此处的adapter是列表的adapter if (!bluetoothList.contains(bleMessage + ">>(已配对)")) { bluetoothList.add(bleMessage + ">>(已配对)"); aAdapter.notifyDataSetChanged(); } } else { if (!bluetoothList.contains(bleMessage + ">>(未配对)")) { bluetoothList.add(bleMessage + ">>(未配对)"); aAdapter.notifyDataSetChanged(); } } } } };
蓝牙搜索
// 搜索蓝牙 private void doSearchBle() { Intent enabler = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE); startActivity(enabler); if (bluetoothList == null || !bluetoothList.isEmpty()) { assert bluetoothList != null; bluetoothList.clear(); aAdapter.notifyDataSetChanged(); } // 如果蓝牙打开,进行广播注册 if (bluetoothAdapter.isEnabled()) { // 蓝牙广播注册 registerBluetooth(); } else { Toast.makeText(MainActivity.this,"蓝牙未开启!",Toast.LENGTH_SHORT).show(); return; } /** * 开启蓝牙服务端 * */ ThreadPoolProxyFactory.getNormalThreadPoolProxy().execute(new Runnable() { @Override public void run() { BltService bltService = new BltService(bluetoothAdapter,app_context); bltService.startBluService(); } }); if (bluetoothAdapter.isDiscovering()) { // 判断蓝牙是否正在扫描,如果是,调用取消方法,如果不是,则开始扫面 bluetoothAdapter.cancelDiscovery(); } bluetoothAdapter.startDiscovery(); }
ListView点击实现
// listView点击的实现 void listViewClick() { ble_list_view.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> adapterView, View view, final int i, long l) { bluetoothAdapter.cancelDiscovery(); String info = bluetoothList.get(i); String[] tempBleInfo = info.split(">>"); String tempAddress; if (tempBleInfo.length < 3) { return; } tempAddress = tempBleInfo[1]; BluetoothDevice de = bluetoothAdapter.getRemoteDevice(tempAddress); if (de.getBondState() == BluetoothDevice.BOND_BONDED) { // 已绑定的进入连接 startConnect(de); } else { // 未绑定的先配对 try { Method createBond = BluetoothDevice.class.getMethod("createBond"); createBond.invoke(de); } catch (Exception e) { e.printStackTrace(); Toast.makeText(MainActivity.this, "无法执行配对", Toast.LENGTH_SHORT).show(); } } } }); }
蓝牙连接
// 与蓝牙设备连接的业务代码 private void startConnect(final BluetoothDevice bluetoothDevice) { // 连接之前把扫描关闭 if (bluetoothAdapter.isDiscovering()) { // 判断蓝牙是否正在扫描,如果是,调用取消方法,如果不是,则开始扫面 bluetoothAdapter.cancelDiscovery(); } ThreadPoolProxyFactory.getNormalThreadPoolProxy().execute(new Runnable() { @Override public void run() { connect(bluetoothDevice); } }); } private int connectsuccess = 12;//连接成功 private void connect(BluetoothDevice bluetoothDevice) { try { mBluetoothSocket = bluetoothDevice.createRfcommSocketToServiceRecord(BltConstant.SPP_UUID); if (mBluetoothSocket != null) { //app_bluetoothSocket = mBluetoothSocket; if (bluetoothAdapter.isDiscovering()) { bluetoothAdapter.cancelDiscovery(); } if (!mBluetoothSocket.isConnected()) { mBluetoothSocket.connect(); } EventBus.getDefault().post(new BluRxBean(connectsuccess, bluetoothDevice)); /** // 蓝牙连接成功后,开启消息接收端,移动到eventBus的主动连接或者被动连接成功之后 ThreadPoolProxyFactory.getNormalThreadPoolProxy().execute(new Runnable() { @Override public void run() { new ReceiveSocketService().receiveMessage(); } }); **/ } } catch (IOException e) { e.printStackTrace(); try { mBluetoothSocket.close(); } catch (IOException e1) { e1.printStackTrace(); } } }
开启蓝牙服务端
public void startBluService() { try { if (BltManager.getInstance().getmBluetoothAdapter() != null) { bluetoothServerSocket = BltManager.getInstance().getmBluetoothAdapter().listenUsingRfcommWithServiceRecord("hlq.bluetooth", BltConstant.SPP_UUID); } } catch (IOException e) { } try { bluetoothServerSocket = bluetoothAdapter.listenUsingRfcommWithServiceRecord(bluetoothAdapter.getDefaultAdapter().getName(), BltConstant.SPP_UUID); socket = bluetoothServerSocket.accept(); if (socket != null) { MainActivity.mBluetoothSocket = socket; EventBus.getDefault().post(new BluRxBean(11, socket.getRemoteDevice())); //如果你的蓝牙设备只是一对一的连接,则执行以下代码 bluetoothServerSocket.close(); //如果你的蓝牙设备是一对多的,则应该调用break;跳出循环 //break; } } catch (IOException e) { e.printStackTrace(); } }
开启蓝牙消息接收端
public void receiveMessage() { if (MainActivity.mBluetoothSocket == null) { return; } try { InputStream inputStream = MainActivity.mBluetoothSocket.getInputStream(); // 从客户端获取信息 BufferedReader bff = new BufferedReader(new InputStreamReader(inputStream)); String json; while (true) { while((json = bff.readLine()) != null) { EventBus.getDefault().post(new MessageBean(RECEIVER_MESSAGE, json)); } } } catch (IOException e) { e.printStackTrace(); } }
通过EventBus实现状态监听与相关功能
@Subscribe(threadMode = ThreadMode.MAIN) public void onMessageEvent(Object obj) { if (obj instanceof MessageBean) { MessageBean messageBean = (MessageBean) obj; switch (messageBean.getId()) { case 21: String msg = messageBean.getContent(); //SendSocketService.sendMessage(String.valueOf(own_step)); // 如果是pk请求,返回自己的步数 if (msg.equals(PkConstant.PK_REQUEST)) { SendSocketService.sendMessage(PkConstant.PK_RESPOND + ":" + String.valueOf(own_step)); } // 如果是pk响应,则进行步数比较 if (msg.startsWith(PkConstant.PK_RESPOND)) { String[] temp = msg.split(":"); int enemy_step; try { enemy_step = Integer.parseInt(temp[1]); stepPk(own_step,enemy_step); } catch (Exception e) { Toast.makeText(MainActivity.this,"接收到非法数据!",Toast.LENGTH_SHORT).show(); } } break; case BltConstant.SEND_TEXT_SUCCESS: //Toast.makeText(MainActivity.this,"发送了数据!",Toast.LENGTH_SHORT).show(); // 发送了消息 break; default: break; } } if (obj instanceof BluRxBean) { BluRxBean bluRxBean = (BluRxBean) obj; switch (bluRxBean.getId()) { case 2: //Toast.makeText(MainActivity.this,"蓝牙扫描完成",Toast.LENGTH_SHORT).show(); break; case 3: Toast.makeText(MainActivity.this,"开始扫描蓝牙...",Toast.LENGTH_SHORT).show(); break; case 4: //Toast.makeText(MainActivity.this,"蓝牙配对成功!",Toast.LENGTH_SHORT).show(); break; case 11: case 12: // 由于状态码11和12分别为被连接和主动连接,所以当两个连接成功之一时,启动消息接收端 ThreadPoolProxyFactory.getNormalThreadPoolProxy().execute(new Runnable() { @Override public void run() { new ReceiveSocketService().receiveMessage(); } }); Toast.makeText(MainActivity.this,"蓝牙已连接",Toast.LENGTH_SHORT).show(); break; default: break; } } }
PK效果展示
以上是关于Android|安卓精准计步器并通过蓝牙实现对战PK功能的主要内容,如果未能解决你的问题,请参考以下文章