zoukankan      html  css  js  c++  java
  • 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效果展示

  • 相关阅读:
    利用UncaughtExceptionHandler捕获未try...catch到的异常
    nodejs
    angularjs异步处理 $q.defer()
    springboot集成swagger
    面试相关
    springboot注解
    关于自动拆装箱
    sonar集成搭建
    Predicate 类
    idea快捷键
  • 原文地址:https://www.cnblogs.com/jlutiger/p/12813243.html
Copyright © 2011-2022 走看看