(安卓)【項目記錄】藍牙app,盲人紅綠燈行走提示

這邊來記錄一下這個盲人指示紅綠燈 藍牙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。那就第二個音頻也進行播放。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章