Android|安卓精准计步器并通过蓝牙实现对战PK功能

greenpepper 2020-05-01

计步器功能实现

本章节功能实现参考:http://blog.csdn.net/linglongxin24/article/details/52868803

记步算法参考

添加权限

<!--计歩需要的权限-->
    <uses-permission android:name="android.permission.VIBRATE" />
    <uses-permission android:name="android.permission.WRITE_SETTINGS" />
    <uses-feature android:name="android.hardware.sensor.accelerometer" />
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
    <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
    <uses-feature
        android:name="android.hardware.sensor.stepcounter"
        android:required="true" />
    <uses-feature
        android:name="android.hardware.sensor.stepdetector"
        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;
    }

功能使用

private boolean isBind = false;
    private Messenger mGetReplyMessenger = new Messenger(new Handler(this));
    private Messenger messenger;

    /**
     * 开启计步服务
     */
    private void setupService() {
        Intent intent = new Intent(this, StepService.class);
        isBind = bindService(intent, conn, Context.BIND_AUTO_CREATE);
        startService(intent);


    }
    /**
     * 从service服务中拿到步数
     *
     * @param msg
     * @return
     */
    @Override
    public boolean handleMessage(Message msg) {
        switch (msg.what) {
            case Constant.MSG_FROM_SERVER:
                cc.setCurrentCount(10000, msg.getData().getInt("step"));
                break;
        }
        return false;
    }


    /**
     * 用于查询应用服务(application Service)的状态的一种interface,
     * 更详细的信息可以参考Service 和 context.bindService()中的描述,
     * 和许多来自系统的回调方式一样,ServiceConnection的方法都是进程的主线程中调用的。
     */
    ServiceConnection conn = new ServiceConnection() {
        /**
         * 在建立起于Service的连接时会调用该方法,目前Android是通过IBind机制实现与服务的连接。
         * @param name 实际所连接到的Service组件名称
         * @param service 服务的通信信道的IBind,可以通过Service访问对应服务
         */
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            try {
                messenger = new Messenger(service);
                Message msg = Message.obtain(null, Constant.MSG_FROM_CLIENT);
                msg.replyTo = mGetReplyMessenger;
                messenger.send(msg);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

        /**
         * 当与Service之间的连接丢失的时候会调用该方法,
         * 这种情况经常发生在Service所在的进程崩溃或者被Kill的时候调用,
         * 此方法不会移除与Service的连接,当服务重新启动的时候仍然会调用 onServiceConnected()。
         * @param name 丢失连接的组件名称
         */
        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    };

效果展示

Android|安卓精准计步器并通过蓝牙实现对战PK功能Android|安卓精准计步器并通过蓝牙实现对战PK功能

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功能

相关推荐