两个Android端基于蓝牙通讯的demo

这几天很不顺利,经过一段时间的疯狂加班之后工作终于辞了,淡定下来回顾下最近所开发的软件,当做整合整合知识。闲话不多说进入正题。

随着硬件成本的不断降低,目前越来越多的终端外设也运行了Android系统,因此在和这些外设做短距离的小数据通讯时Android与Android的蓝牙通讯成为了主力军,本次采用的是socket蓝牙通讯,熟悉socket的同学肯定知道,socket通讯肯定就有服务器端和客户端,我们先来介绍服务器的代码:

老样子我们先介绍下界面布局,本服务器端有两个页面,分别是蓝牙配对页面和收发接口页面,如下图:

                                                               

上图第一个界面是蓝牙的配对界面,打开软件会列出已配对的设备,点击扫面按键会扫描附近的蓝牙设备(如果长时间不能够扫面到设备建议先使用系统进行配对),点击相应的需连接设备后进入第二个界面,等待客户端的连接,具体代码如下:

蓝牙扫描页面:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.viewat.bluetooth.MainActivity" >
    
    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="搜索设备"
        android:onClick="onClick_search"/>
    
    <TextView 
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="60dp"
        android:text="蓝牙设备列表"
        android:layout_centerHorizontal="true"/>
    
    <ListView 
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="80dp"
        android:id="@+id/listView">
    </ListView>

</RelativeLayout>

蓝牙收发操作界面:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" 
    android:background="@android:color/white">
    
    
    <ScrollView 
        android:layout_width="match_parent"
        android:layout_height="300dp"
        android:paddingLeft="10dp"
        android:paddingRight="10dp">
       	<TextView
       	    android:layout_width="match_parent"
       	    android:layout_height="wrap_content"
       	    android:id="@+id/tv_message"/>
    </ScrollView>
    
    <EditText 
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:layout_alignParentBottom="true"
        android:layout_marginBottom="80dp"
        android:id="@+id/editText"/>
    
    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_marginBottom="20dp"
        android:layout_marginLeft="30dp"
        android:text="发送"
        android:onClick="onClick_send"/>
    
    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_marginBottom="20dp"
        android:layout_alignParentRight="true"
        android:layout_marginRight="30dp"
        android:text="结束回话,断开链接"
        android:onClick="onClick_end"/>
    
</RelativeLayout>
下面介绍实现的代码,首先是获取已配对的蓝牙设备罗列出来:

	/**
     * 列出所有的蓝牙设备
     */
    private void init() {
        Log.i("tag", "mBtAdapter=="+ mBtAdapter);
        //根据适配器得到所有的设备信息
        Set<BluetoothDevice> deviceSet = mBtAdapter.getBondedDevices();
        if (deviceSet.size() > 0) {
            for (BluetoothDevice device : deviceSet) {
                mDatas.add(new DeviceBean(device.getName() + "\n" + device.getAddress(), true));
                mAdapter.notifyDataSetChanged();
                mListView.setSelection(mDatas.size() - 1);
            }
        } else {
            mDatas.add(new DeviceBean("没有配对的设备", true));
            mAdapter.notifyDataSetChanged();
            mListView.setSelection(mDatas.size() - 1);
        }
    }
利用广播获取所有的蓝牙设备:

    /**
     * 发现设备广播
     */
    private final BroadcastReceiver mReceiver = 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);
                // 如果绑定的状态不一样
                if (device.getBondState() != BluetoothDevice.BOND_BONDED) {
                    mDatas.add(new DeviceBean(device.getName() + "\n" + device.getAddress(), false));
                    mAdapter.notifyDataSetChanged();
                    mListView.setSelection(mDatas.size() - 1);
                }
                
            // 如果搜索完成了
            } else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) {
                setProgressBarIndeterminateVisibility(false);
                if (mListView.getCount() == 0) {
                    mDatas.add(new DeviceBean("没有发现蓝牙设备", false));
                    mAdapter.notifyDataSetChanged();
                    mListView.setSelection(mDatas.size() - 1);
                }
                showTxt("请重新搜索");
            }
        }
    };


接着监听点击事件,进入连接页面:

 /**
     * 点击设备监听
     */
    private OnItemClickListener mDeviceClickListener = new OnItemClickListener() {
        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {

            DeviceBean bean = mDatas.get(position);
            String info = bean.message;
            String address = info.substring(info.length() - 17);
            BlueToothAddress = address;

            AlertDialog.Builder stopDialog = new AlertDialog.Builder(MainActivity.this);
            stopDialog.setTitle("连接");//标题
            stopDialog.setMessage(bean.message);
            stopDialog.setPositiveButton("连接", new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int which) {
                    mBtAdapter.cancelDiscovery();
//                    showTxt("停止扫描,进行连接...");

                    startActivity(new Intent(MainActivity.this,ChatActivity.class));
                    dialog.cancel();
                }
            });
            
            stopDialog.setNegativeButton("取消", new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int which) {
                    BlueToothAddress = null;
                    dialog.cancel();
                }
            });
            stopDialog.show();
        }
    };


紧接着会跳转到蓝牙的收发页面,首先获得一个蓝牙适配器 mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); 接着会打开监听的线程;

	// 开启服务器
    private class ServerThread extends Thread {
        public void run() {
            try {
                // 创建一个蓝牙服务器 参数分别:服务器名称、UUID
                mServerSocket = mBluetoothAdapter.listenUsingRfcommWithServiceRecord(PROTOCOL_SCHEME_RFCOMM,
                        UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"));

                Message msg = new Message();
                msg.obj = "请稍候,正在等待客户端的连接...";
                msg.what = STATUS_CONNECT;
                mHandler.sendMessage(msg);

                /* 接受客户端的连接请求 */
                mSocket = mServerSocket.accept();

                msg = new Message();
                msg.obj = "客户端已经连接上!可以发送信息。";
                msg.what = STATUS_CONNECT;
                mHandler.sendMessage(msg);
                // 启动接受数据
                mReadThread = new ReadThread();
                mReadThread.start();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }; 
此时服务端的代码准备完成,下面我们介绍下客户端代码,同样的客户端也是有类似的两个页面,如下图:

                                                                              

当打开服务端的监听后,打开客户端的代码会进入蓝牙配对的界面,点击相应的服务端设备进入蓝牙操作界面,点击open后会进行和服务端连接,连接成功后会进行相应的提醒,此时既可以进行通讯了,具体的界面代码如下:
蓝牙扫面界面:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.viewat.bluetooth.MainActivity" >
    
    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="搜索设备"
        android:onClick="onClick_search"/>
    
    <TextView 
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="60dp"
        android:text="蓝牙设备列表"
        android:layout_centerHorizontal="true"/>
    
    <ListView 
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="80dp"
        android:id="@+id/listView">
    </ListView>

</RelativeLayout>

蓝牙收发界面:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.viewat.bluetoothhostclient.MainActivity" >
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="客户端"
        android:layout_centerHorizontal="true"/>

    <Button 
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        android:text="open"
        android:onClick="onClick_open"/>
    
    <Button 
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="20dp"
        android:text="send"
        android:onClick="onClick_send"/>
    
    <Button 
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:layout_marginTop="20dp"
        android:text="close"
        android:onClick="onClick_close"/>
    

    <EditText 
        android:layout_width="match_parent"
        android:layout_height="40dp"
        android:layout_marginTop="100dp"
        android:id="@+id/editText"/>
    
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="160dp"
        android:paddingLeft="10dp"
        android:paddingRight="10dp"
        android:text="数据"
        android:id="@+id/tv_message"/>

</RelativeLayout>

下面介绍客户端的实现,监听蓝牙列表的点击事件和服务端类似,连接服务端时同样先构建一个蓝牙适配器 mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();紧接着以给定的MAC地址去创建一个 BluetoothDevice 类实例 mDevice = mBluetoothAdapter.getRemoteDevice(address);然后开启客户端的连接线程:

// 客户端线程
    private class ClientThread extends Thread {
        public void run() {
            try {
                mSocket = mDevice.createRfcommSocketToServiceRecord(UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"));
                Message msg = new Message();
                msg.obj = "请稍候,正在连接服务器:" + address;
                msg.what = STATUS_CONNECT;
                mHandler.sendMessage(msg);

                mSocket.connect();

                msg = new Message();
                msg.obj = "已经连接上服务端!可以发送信息。";
                msg.what = STATUS_CONNECT;
                mHandler.sendMessage(msg);
                // 启动接受数据
                mReadThread = new ReadThread();
                mReadThread.start();
                isOpen = true;
            } catch (Exception e) {
                Message msg = new Message();
                msg.obj = "连接服务端异常!请断开连接重新试一试。";
                msg.what = STATUS_CONNECT;
                mHandler.sendMessage(msg);
            }
        }
    };

在连接线程之后会开启接收数据的线程,然后利用回调显示在界面上:

 // 读取数据
    private class ReadThread extends Thread {
        public void run() {
            byte[] buffer = new byte[1024];
            int bytes;
            InputStream is = null;
            try {
                is = mSocket.getInputStream();
                while (true) {
                    if ((bytes = is.read(buffer)) > 0) {
                        byte[] buf_data = new byte[bytes];
                        for (int i = 0; i < bytes; i++) {
                            buf_data[i] = buffer[i];
                        }
                        
                        String s = new String(buf_data);
                        Message msg = new Message();
                        Bundle bundle = msg.getData();
                        bundle.putString("info", s);
                        bundle.putByteArray("buf", buf_data);
                        mHandler.sendMessage(msg);
                    }
                }
            } catch (Exception e1) {
                e1.printStackTrace();
            } finally {
                try {
                    is.close();
                } catch (Exception e1) {
                    e1.printStackTrace();
                }
            }

        }
    }

致此整个蓝牙收发的客户端和服务端已经全部写完,这里废话下软件的操作流程:

服务端:
进入主界面后,找到对应的手机的蓝牙mac地址,点击后进入聊天界面。
遇到弹框就点同意。

客户端:
进入主界面后,找到对应的手机的蓝牙mac地址,点击后进入聊天界面。
遇到弹框就点同意。
点击open,然后弹框上点击同意,在服务端上显示"客户端已经连接上,可以发送信息",表示能进行通讯了

最后贴上我的源代码:源码下载(辛苦手打收两个积分大笑,如果积分不够可在下面留下邮箱,我看到后第一时间发送源码)

纯手打,有帮助就回复下,有什么问题也可留言,我们共同讨论下。

转载请注明出处!谢谢!


评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值