Android 蓝牙串口调试程序开发

前言:本次项目需要为智能设备开发一个 App 于是就开始学习 Android 的蓝牙串口通信方面的知识,现在 App 已经写完了,当初学的时候走了不少弯路和尝试,现作为一名初学者和大家分享一下经验,以及总结我该部分的学习。


〇、蓝牙串口开发的流程

开始

获取权限

检测设备

打开蓝牙

连接设备

收发数据

单片机串口蓝牙

结束

yes

no

yes

no

一、添加需要用到的权限

在 Android 项目中,打开 AndroidManif.xml 文件 添加对蓝牙操作的权限。


    <uses-permission android:name="android.permission.BLUETOOTH" />

    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />

    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />


二、检测和打开蓝牙设备

1.检测蓝牙设备

如果要通过蓝牙进行串口通信,必须得保证蓝牙设备正常工作,首先要检测蓝牙设备是否正常。通常情况下这一步也可以省略,或在打开蓝牙设备的时候检测。


//获取默认蓝牙设备

mADAPTER_BLUETOOTH = BluetoothAdapter.getDefaultAdapter();

//判断是否有蓝牙设备

if (mADAPTER_BLUETOOTH == null){

Toast.makeText(MainActivity.this, "未找到蓝牙功能", LENGTH_SHORT).show();

}else {

Toast.makeText(MainActivity.this, "蓝牙功能正常", LENGTH_SHORT).show();


通过 BluetoothAdapter 来获取默认蓝牙设备,值为 null 说明蓝牙功能缺失,反之则反。

郑州哪个不孕不育医院好:http://jbk.39.net/yiyuanfengcai/tsyl_zztjyy/1451/

2.打开蓝牙设备

打开蓝牙设备的方式一共有两种,一种是直接通过使能蓝牙打开,另一种是弹出对话框让用户确认打开。一般不使用第一种,而使用有交互的第二种。因为如果我们打开蓝牙,不打开蓝牙可见的话,别人就发现不了我们的设备,对我们的项目没有任何意义,所以在打开蓝牙的同时会打开可见。

郑州好的不孕不育医院有哪些:http://www.xasgnk.com/

直接使能蓝牙的方式

mADAPTER_BLUETOOTH = BluetoothAdapter.getDefaultAdapter();

mADAPTER_BLUETOOTH.enable();

1

2

具有人机交互的方式


构建一个打开蓝牙的方法,可以把对蓝牙操作的方法,写在一个类里面,方便调用。


//打开蓝牙的方法

public void TurnOnBlueTooth(){

    //获取默认蓝牙设备

    mADAPTER_BLUETOOTH = BluetoothAdapter.getDefaultAdapter();

    //判断是否有蓝牙设备

    if (mADAPTER_BLUETOOTH == null){

        Toast.makeText(MainActivity.this, "未找到蓝牙功能", LENGTH_SHORT).show();

    }else {

        Toast.makeText(MainActivity.this, "蓝牙功能正常", LENGTH_SHORT).show();

        if (!mADAPTER_BLUETOOTH.isEnabled()){

            //如果蓝牙设备正常 蓝牙没打开 请求打开并可见

            Intent TurnOn = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);

            startActivityForResult(TurnOn,1);

        }else {

            Toast.makeText(MainActivity.this, "蓝牙已打开 请勿重复打开", LENGTH_SHORT).show();

        }

    }

}


蓝牙状态的广播接收者


通过注册一个蓝牙状态的广播接收者,来接收蓝牙状态改变,给用户提供一个跟友好的人机交互。


注册广播接收者


//蓝牙状态改变的广播 //注册和绑定广播接收者和广播

IntentFilter mBROADCAST_BLUETOOTH_STATE = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);

registerReceiver(RECEIVER_BLUETOOTH_STATE,mBROADCAST_BLUETOOTH_STATE);


写蓝牙状态改变的广播接收者


//蓝牙打开状态的广播接收

private BroadcastReceiver RECEIVER_BLUETOOTH_STATE = new BroadcastReceiver() {

    @Override

    public void onReceive(Context context, Intent intent) {

        int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,-1);

        switch (state){

            case BluetoothAdapter.STATE_OFF:

                Toast.makeText(MainActivity.this, "蓝牙已关闭", LENGTH_SHORT).show();

                break;

            case BluetoothAdapter.STATE_ON:

                Toast.makeText(MainActivity.this, "蓝牙已打开", LENGTH_SHORT).show();

                break;

            case BluetoothAdapter.STATE_TURNING_OFF:

                Toast.makeText(MainActivity.this, "蓝牙正在关闭", LENGTH_SHORT).show();

                break;

            case BluetoothAdapter.STATE_TURNING_ON:

                Toast.makeText(MainActivity.this, "蓝牙正在打开", LENGTH_SHORT).show();

                break;

        }

    }

};


通过接受蓝牙状态改变的广播,来给用户相应的提示,形成良好的人机交互。


三、搜索并连接蓝牙设备

1.搜索蓝牙设备

搜索蓝牙设备操作直接调用 BluetoothAdapter 的 startDiscovery 方法即可。同样的,我们可以写一个搜索蓝牙的方法,把这个方法写在 对蓝牙操作的 类里面,方便我们去调用。


public void DiscoveryBlueTooth() {

    //获取默认的蓝牙设备

    mADAPTER_BLUETOOTH = BluetoothAdapter.getDefaultAdapter();

    //判断是否在搜索

    if (mADAPTER_BLUETOOTH.isDiscovering()) {

        mADAPTER_BLUETOOTH.cancelDiscovery();

    }

    //开始搜索

    mADAPTER_BLUETOOTH.startDiscovery();

    Toast.makeText(MainActivity.this, "蓝牙设备正在搜索中", LENGTH_SHORT).show();

}


这只是开启搜索,我们搜索的结果该怎么反馈给我们呢?我们需要一个容器来存放我们刚刚搜索到的设备。


ListView 和 ListAdapter

我们在布局文件中,加入一个Listview控件,来显示我们搜索到的蓝牙设备。写好布局后,给 Listview 的 item 写一个布局样式。

<TextView

    android:id="@+id/TV_BLUETOOTH_DEVICE"

    android:layout_width="match_parent"

    android:layout_height="50dp"

    android:textSize="13sp"

    android:textColor="@color/colorWhite"

    android:background="@drawable/button_selector"/>


我这里只用了一个 Textview

写好了 Listview 我们需要一个东西,把搜索到的设备信息和 Listview 的内容绑定起来。这里我用的是 ArrayList ,通过 ArrayAdapter 绑定设备信息和 Listview的内容。


//ArrayAdapter声明

private ArrayAdapter mADAPTER_ARRAY;

//ArrayList定义:存放蓝牙名称和地址

private List<String> BLUETOOTH_DEViCE = new ArrayList<>();


/*

*通过 ArrayAdapter 绑定 ListView控件和ArrayList里的数据

*/

//通过ArrayAdapter绑定数据

mADAPTER_ARRAY = new ArrayAdapter<String>(this,R.layout.list_view_item,R.id.TV_BLUETOOTH_DEVICE,BLUETOOTH_DEViCE);

//给ListView使用这个 adapter

mLV_DEVICE.setAdapter(mADAPTER_ARRAY);


到这里,我们的准备工作就完成了,接下来就是把搜索到的设备信息添加进去。


接收搜索结果的广播

在接受搜索设备的广播之前,先注册搜索设备的广播,将接收者和广播绑定。

//蓝牙状态改变的广播 //注册和绑定广播接收者和广播

IntentFilter mBROADCAST_BLUETOOTH_STATE = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);

registerReceiver(RECEIVER_BLUETOOTH_STATE,mBROADCAST_BLUETOOTH_STATE);


然后写搜索蓝牙设备的广播接收者


private BroadcastReceiver RECEIVER_BLUETOOTH_FOUND = new BroadcastReceiver() {

        @Override

        public void onReceive(Context context, Intent intent) {

            String action = intent.getAction();

            if (BluetoothDevice.ACTION_FOUND.equals(action)) {

                BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);

                BLUETOOTH_DEViCE.add("  NAME:"+device.getName()+"(待连接)"+"\n"+"  *MAC:"+device.getAddress());

                mADAPTER_ARRAY.notifyDataSetChanged();

            }

        }

    };


将搜索到的设备添加到 ArrayList 里,然后就会在 Listview 上显示。


2.连接蓝牙设备

在完成了搜索设备之后,我们就需要与蓝牙设备进行连接。与单片机上蓝牙串口连接,我们需要蓝牙串口服务的 UUID 00001101-0000-1000-8000-00805F9B34FB

需要一个 Sokect 来连接蓝牙串口。


//设定本机的UUID->通用唯一识别码 //串口UUID

private final UUID mUUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");

//定义BluetoothSocket

public static BluetoothSocket mBLUETOOTH_SOCKET;


我们给 Listview 的 item 设立一个点击事件,好让我们点击一个设备的时候,可以连接该设备。在点击事件中,我们通过 ArrayAdapter 的 getItem 方法,来获取保存在 Array List里面的设备信息。然后通过 “*” 定位我们需要的地址的起始位置,来获取地址。通过 BluetoothDevice 的 GetRemoteDevice 方法,获取该地址的的设备。用我们写的 ConnectThread 的方法进行连接设备。


//LV_DEVICE 的 item 被点击:

mLV_DEVICE.setOnItemClickListener(new AdapterView.OnItemClickListener() {

    @Override

    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {

        //BluetoothDevice mBTD =

        //获取item的内容 //解析出内容里的地址

        String s = (String) mADAPTER_ARRAY.getItem(position);

        if (mADAPTER_BLUETOOTH.isDiscovering())

        {

            mADAPTER_BLUETOOTH.cancelDiscovery();

        }

        if (s != null){

        //在这里我们通过*来定位地址的起始字符然后保存在 address里

            String address = s.substring(s.indexOf("*")+5).trim();

            Toast.makeText(MainActivity.this,"MAC:"+address,Toast.LENGTH_LONG).show();

            BluetoothDevice device = mADAPTER_BLUETOOTH.getRemoteDevice(address);

            ConnectThread(device);

        }



    }

});


ConnectThread 方法

进行连接后,我们就开始数据接收服务


public void ConnectThread(BluetoothDevice device) {

    try {

        mBLUETOOTH_SOCKET = device.createRfcommSocketToServiceRecord(mUUID);

        mADAPTER_BLUETOOTH.cancelDiscovery();

        mBLUETOOTH_SOCKET.connect();

        Toast.makeText(MainActivity.this, "连接成功", Toast.LENGTH_LONG).show();

        // 接收数据进程

        ReceiveData receiveThread = new ReceiveData();

        // 连接成功后开启接收数据服务

        receiveThread.start();

    } catch (IOException e) {

        Toast.makeText(MainActivity.this, "连接失败", Toast.LENGTH_SHORT)

                .show();

        try {

            mBLUETOOTH_SOCKET.close();

        } catch (IOException e2) {

            e.printStackTrace();

        }

    }

}


既然要连接我们就要有一个取消连接的方法。关闭 Socket 来释放资源。


    // 取消链接的方法

    public void CancelConnect() {

        try {

            mBLUETOOTH_SOCKET.close();

        } catch (IOException e) {

            e.printStackTrace();

        }

    }


在以上过程中,我们可以自己设立一个 Boolean 型的变量,来表示与设备的连接状态,通过判断该变量的值来做出相应的人机交互。


四、发送并接受串口数据

到这一步,我们的项目基本成型了,只剩下最后也是最关键的与 串口蓝牙进行通信。我这里采用的是发送 字符数据 和 接受 字符数据 进行交互。在发送的时候,会将字符数据转化成字节流的形式发送。


1.发送数据部分

发送数据数据和接受数据,我们需要 输入流 和 输出流。


    //定义输出流//定义输入流

    public static OutputStream OS;

    public static InputStream  IS;


然后写一个 write 的方法来调用 OutputStream 的 write 方法来写一个字节。


    //发送数据的方法

    public static void write(String str) {

        if (CONNECT_STATUS) {

            try {

                OS = mBLUETOOTH_SOCKET.getOutputStream();

                if (OS != null){

                    OS.write(str.getBytes("UTF-8"));

                }

            } catch (IOException e) {

                e.printStackTrace();

            }

        }

    }


我们可以将 String 来源于 Edit Text 控件的内容,通过一个按钮来执行发送的操作。


2.接收数据部分

接受数据的服务我们已经在连接那一步打开了,里面用到的我们写的一个接收数据的方法 ReceiveData 。并且在调用前,我们开启了一个新的线程来做这件事情。


    // 读数据线程

    private class ReceiveData extends Thread {

        InputStream mmInStream;


        private ReceiveData() {

            try {

                mmInStream = mBLUETOOTH_SOCKET.getInputStream();

            } catch (IOException e) {

                e.printStackTrace();

            }

        }


        @Override

        public void run() {


            int bytes = 0;

            byte[] buffer = new byte[256];

            while (true) {


                // 接收数据

                try {

                    bytes = mmInStream.read(buffer);

                    final String readString = new String(buffer, 0, bytes);


                    runOnUiThread(new Runnable() {

                        @Override

                        public void run() {

                            mTV_ACCEPT.append(readString + " ");

                        }

                    });

                } catch (IOException e) {

                    e.printStackTrace();

                }

            }

        }

    }


我们可以用一个 Textview 用来显示我们接收到的数据。


五、总结学习

本次项目的学习主要难点在搜索添加设备和,读写数据上,很多内容还需要多家理解,对该部分的知识还不够深刻,需要系统性的学习一下。



猜你喜欢

转载自blog.51cto.com/14510351/2494988