这边来记录一下这个盲人指示红绿灯 蓝牙app的制作过程。

第一步:安装一个android studio 具体过程不写了。直接下载安装就行

第二步: 新建项目 file -> new -> newProject,选择Empty Activity

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EC6anZFL-1586166531716)(https://i.loli.net/2020/04/06/U9waJ2F3zHdXMGf.png)]

language选择java 最小api选择23 一般现在手机都比6.0高吧

第三步:添加两个textview 用来显示一定的信息。id 分别取为tip1,tip2

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IWzjbjjk-1586166531718)(https://i.loli.net/2020/04/06/WjExD1Xd54LPCNc.png)]

第四步 初始化界面

在oncreate 函数中 添加.意思是代码获取到那两个text控件。方便后面动态的改变信息。

tip=findViewById(R.id.tip);
tip2=findViewById(R.id.tip2);
tip.setText("蓝牙已断开");

也需要在类中声明变量

TextView tip,tip2;

第五步 构建蓝牙连接层。

声明变量

BluetoothDevice device;
BluetoothSocket mSocket;
BluetoothAdapter mBluetoothAdapter;

构建线程函数,是一个跑在单独线程里的死循环。

安卓新版本都要动态申请权限。所以首先申请权限

下一步 循环检测设备有没有绑定。没绑定得先去绑定。

然后是 进行一个链接和通讯。每次循环前判断一次连接状态。如果正常就读取蓝牙数据。不正常就进行重连

public void bluetoothinit(){
        Log.e("myTip123","开始线程");
        mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
        if (mBluetoothAdapter == null) {
            // Device does not support Bluetooth
        }
        if (!mBluetoothAdapter.isEnabled()) {//申请权限 ask for permission
            Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
            startActivityForResult(enableBtIntent, 1);
        }

        while (true){
            Set<BluetoothDevice> tmp = mBluetoothAdapter.getBondedDevices();


            for (BluetoothDevice d : tmp) {
                Log.e("add123",d.getAddress());
                if(d.getAddress().equals("00:19:10:08:A5:3C")){
                    device=d;
                }
            }
            if(device==null){
                Log.e("myTip123","设备未绑定。请绑定后再试。");
                MainActivity.this.runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        Toast.makeText(MainActivity.this.getApplicationContext(), "设备未绑定。请绑定后再试。", Toast.LENGTH_LONG).show();
                        Log.e("myTip123","设备未绑定。请绑定后再试。");
                    }
                });
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }else{
                break;
            }
        }

        // 所有已绑定设备,一个Set集合

        try {
            mSocket = device.createRfcommSocketToServiceRecord(UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"));
        } catch (IOException e) {

            e.printStackTrace();

        }
        mBluetoothAdapter.cancelDiscovery();
        while(true){
            Log.e("myTip123","检查");
            if(mSocket.isConnected()){
                try {
                    String hhh="";
                    while(mSocket.getInputStream().available()>0){
                        hhh+=(char)mSocket.getInputStream().read();
                    }
                    Log.e("myTip123",hhh);
                    int lastDirectionFlag=DirectionFlag;
                    DirectionFlag=(hhh.contains("NSpass")?1:2);
                    if(lastDirectionFlag!=DirectionFlag){//方向改变

                        Log.e("方向改变",""+DirectionFlag);
                        tip.setText("蓝牙已链接 "+(DirectionFlag==1?"南北通":"东西通"));
                        if(DirectionFlag==2){//东西
                            if(dir==3){//南
                                play(ns,gono);
                            }else if(dir==2){
                                play(ew,goyes);
                            }
                        }
                        else if(DirectionFlag==1){
                            if(dir==3){//南
                                play(ns,goyes);
                            }else if(dir==2){
                                play(ew,gono);
                            }
                        }
                    }
                } catch (IOException e) {
                    Log.e("myTip123","检测available 出错");
                    e.printStackTrace();
                }
                try {
                    mSocket.getOutputStream().write(" ".getBytes());
                } catch (IOException e) {
                    e.printStackTrace();
                    try {
                        mSocket.close();
                    } catch (IOException e1) {
                        e1.printStackTrace();
                    }
                    MainActivity.this.runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            Toast.makeText(MainActivity.this.getApplicationContext(), "蓝牙已断开", Toast.LENGTH_LONG).show();
                            tip.setText("蓝牙已断开");
                            DirectionFlag=0;
                            play(bno,null);
                        }
                    });
                }
            }
            if(!mSocket.isConnected()){
                try {
                    mSocket = device.createRfcommSocketToServiceRecord(UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"));
                    mSocket.connect();

                    MainActivity.this.runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            Toast.makeText(MainActivity.this.getApplicationContext(), "蓝牙已连接", Toast.LENGTH_LONG).show();
                            tip.setText("蓝牙已链接");
                            play(byes,null);
                        }
                    });

                } catch (IOException e) {
                    try {
                        mSocket.close();
                    } catch (IOException e1) {
                        e1.printStackTrace();
                    }
                    MainActivity.this.runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            Toast.makeText(MainActivity.this.getApplicationContext(), "链接失败。未找到设备。5秒后重新链接", Toast.LENGTH_LONG).show();
                        }
                    });
                    e.printStackTrace();
                }
            }


            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

第六步。在oncreate中加入蓝牙线程的启动

new Thread (new Runnable(){
            @Override
            public void run(){
                bluetoothinit();
            }
        }).start();

第七步。读取数据

上面的蓝牙代码里已经有内容了。这边拿出来看一下

String hhh="";
while(mSocket.getInputStream().available()>0){
    hhh+=(char)mSocket.getInputStream().read();
}

第八步。处理数据。

我们要做的就是判断红绿灯方向是否变化。并且做一个提醒。

变化这种就需要记录这一次和上一次的状态。

所以先创建flag变量

初始化

int DirectionFlag=0;int lastDirectionFlag=DirectionFlag;

然后在上面读取完数据后面对当前方向状态进行赋值,通过判断消息中有没有关键字

DirectionFlag=(hhh.contains("NSpass")?1:2);

如果发生了方向改变。我们进行提示。

显示设置文本 flag为1就是南北通。为2就是东西通

然后后面的是根据指南针数据进行对应的音频提示。这部分我们接下来讲

if(lastDirectionFlag!=DirectionFlag){//方向改变

    Log.e("方向改变",""+DirectionFlag);
    tip.setText("蓝牙已链接 "+(DirectionFlag==1?"南北通":"东西通"));
    if(DirectionFlag==2){//东西
         if(dir==3){//南
         play(ns,gono);
    }else if(dir==2){
        play(ew,goyes);
     }
	}
	else if(DirectionFlag==1){
    	if(dir==3){//南
         	play(ns,goyes);
    	}else if(dir==2){
        	play(ew,gono);
    	}
	}
}

第八步。获取指南针数据

添加变量

private Sensor mAccelerometer;
    private Sensor mMagneticField;
    private float[] values = new float[3];   //orientation values
    private float[] accelerometerValues = new float[3];  //data of acclerometer sensor
    private float[] magneticFieldValues = new float[3] ; //data of magnetic field sensor
    private float[] r = new float[9];

在oncreate中初始化

SensorManager mSensorManager;

        mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
        if(mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD) != null){

            //Success!存在磁力计
        }else{
            //Failure!不存在磁力计
        }
        mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
        mMagneticField = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
        mSensorManager.registerListener((SensorEventListener) this, mAccelerometer, SensorManager.SENSOR_DELAY_NORMAL);
        mSensorManager.registerListener((SensorEventListener) this, mMagneticField, SensorManager.SENSOR_DELAY_NORMAL);

给当前类添加接口SensorEventListener,即修改为

public class MainActivity extends AppCompatActivity implements SensorEventListener{


添加override函数

@Override
    public void onSensorChanged(SensorEvent sensorEvent) {
        if (sensorEvent.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
            accelerometerValues = sensorEvent.values;
        }
        if (sensorEvent.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) {
            magneticFieldValues = sensorEvent.values;
        }
        SensorManager.getRotationMatrix(r, null, accelerometerValues, magneticFieldValues);
        SensorManager.getOrientation(r, values);
        values[0] = (float) Math.toDegrees(values[0]);
        dirnum=(int)values[0];
        lastdir=dir;
        if(dirnum>160||dirnum<-160||(dirnum<20&&dirnum>-20)){
            dir=3;
        }else if((dirnum<-70&&dirnum>-110)||(dirnum>70&&dirnum<110)){
            dir=2;
        }else{
            dir=1;
        }
        if(dir!=lastdir){
            MediaPlayer tar = null;
            if (dir== 1){
                play(dirno,null);
            }else{
                if(DirectionFlag==2){//东西
                    if(dir==3){//南
                        play(ns,gono);
                    }else if(dir==2){
                        play(ew,goyes);
                    }
                }
                else if(DirectionFlag==1){
                    if(dir==3){//南
                        play(ns,goyes);
                    }else if(dir==2){
                        play(ew,gono);
                    }
                }
            }


        }
        switch (dir){
            case 1:
                tip2.setText("方向偏离过大");
                break;
            case 2:
                tip2.setText("东西 "+dirnum);


                break;
            case 3:
                tip2.setText("南北 "+dirnum);

                break;
        }

    }

    @Override
    public void onAccuracyChanged(Sensor sensor, int i) {

    }

在以上函数中。对不同角度进行分类。即东西方向,南北方向,还有一个是偏离较大。就是介于东西和南北之间的。比较模糊的方向、

并且给全局的放前方向flag进行设置,同时更新text显示,并做语音提示。


第九步。语音提示

用到的是MediaPlayer。

实现准备的音频文件有。

蓝牙已连接。蓝牙已断开。可以前行。不可前行。方向偏离大。当前方向为南北。当前方向为东西。

MediaPlayer goyes;//
MediaPlayer gono;
private MediaPlayer dirno;
private MediaPlayer byes;
private MediaPlayer bno;
private MediaPlayer ns;
private MediaPlayer ew;

然后我们进入到oncreate中添加对以上几个mediaplayer的加载

goyes = MediaPlayer.create(MainActivity.this.getApplicationContext(), R.raw.goyes);
        gono = MediaPlayer.create(MainActivity.this.getApplicationContext(), R.raw.gono);
        bno = MediaPlayer.create(MainActivity.this.getApplicationContext(), R.raw.bno);
        byes = MediaPlayer.create(MainActivity.this.getApplicationContext(), R.raw.byes);
        dirno = MediaPlayer.create(MainActivity.this.getApplicationContext(), R.raw.dirno);
        ns = MediaPlayer.create(MainActivity.this.getApplicationContext(), R.raw.ns);
        ew = MediaPlayer.create(MainActivity.this.getApplicationContext(), R.raw.ew);

采用的方案是安卓里的raw 资源,需要在项目下的app/src/main/res下新建一个raw 文件夹。然后把音频文件拖放进去。

由于我们的音频可能是两个要连续播放所以我构造了一下函数

MediaPlayer first,second;
    public void play(MediaPlayer tar1, final MediaPlayer tar2){
        if (first!=null){
            first.pause();
            first.seekTo(0);
        }
        if(second!=null){
            second.pause();
            second.seekTo(0);
        }
        first=tar1;
        second=tar2;
        first.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
            @Override
            public void onCompletion(MediaPlayer mp) {
                if(tar2!=null)
                tar2.start();
            }
        });
        first.start();
    }

前两个判断是为了防止开始放当前音频的时候。之前的音频还没播放完。所以要先停止。

然后给第一个音频添加一个播放完毕的事件。如果有第二个音频不为null。那就第二个音频也进行播放。