Android Studio开发之蓝牙通信

安卓开发-蓝牙通信

功能需求:在微信程序的第一子项中完成“蓝牙聊天功能”
开发步骤:

  1. 配置文件注册
  2. 设计界面布局
  3. 编写用于蓝牙会话的服务组件ChatService
  4. 分别建立供主Activity使用的菜单文件res/menu/optionmenu.xml、选择好友(即已经配对过的蓝牙设备)的界面布局文件devicelist.xml
  5. 新建Activity组件DeviceList,实现选取与之会话的蓝牙设备

部分代码展示:

配置文件注册

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.mywechat">
    <uses-permission android:name="android.permission.READ_CONTACTS"/>
    <uses-permission android:name="android.permission.WRITE_CONTACTS" />
    <uses-permission android:name="android.permission.BLUETOOTH"/>
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>

界面布局

<resources>
    <string name="app_name">MyWeChat</string>

    <string name="send">发送</string>
    <string name="not_connected">你没有链接一个设备</string>
    <string name="bt_not_enabled_leaving">蓝牙不可用,离开聊天室</string>
    <string name="title_connecting">链接中...</string>
    <string name="title_connected_to">连接到:</string>
    <string name="title_not_connected">无链接</string>
    <string name="scanning">蓝牙设备搜索中...</string>
    <string name="select_device">选择一个好友链接</string>
    <string name="none_paired">没有配对好友</string>
    <string name="none_found">附近没有发现好友</string>
    <string name="title_paired_devices">已配对好友</string>
    <string name="title_other_devices">其它可连接好友</string>
    <string name="button_scan">搜索好友</string>
    <string name="connect">我的好友</string>
    <string name="discoverable">设置在线</string>
    <string name="back">退出</string>
    <string name="startVideo">开始聊天</string>
    <string name="stopVideo">结束聊天</string>

    <!-- TODO: Remove or change this placeholder text -->
    <string name="hello_blank_fragment">Hello blank fragment</string>
</resources>


<android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="horizontal">
            <TextView
                android:id="@+id/title_left_text"
                style="?android:attr/windowTitleStyle"
                android:layout_width="0dp"
                android:layout_height="match_parent"
                android:layout_alignParentLeft="true"
                android:layout_weight="1"
                android:gravity="left"
                android:ellipsize="end"
                android:singleLine="true" />
            <TextView
                android:id="@+id/title_right_text"
                android:layout_width="0dp"
                android:layout_height="match_parent"
                android:layout_alignParentRight="true"
                android:layout_weight="1"
                android:ellipsize="end"
                android:gravity="right"
                android:singleLine="true"
                android:textColor="#fff" />
        </LinearLayout>
    </android.support.v7.widget.Toolbar>

    <ListView android:id="@+id/in"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:stackFromBottom="true"
        android:transcriptMode="alwaysScroll"
        android:layout_weight="1" />
    <LinearLayout
        android:orientation="horizontal"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" >
        <EditText android:id="@+id/edit_text_out"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:layout_gravity="bottom" />
        <Button android:id="@+id/button_send"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/send"/>
    </LinearLayout>

在这里插入图片描述
ChatService

//取消 CONNECTING 和 CONNECTED 状态下的相关线程,然后运行新的 mConnectThread 线程
        public synchronized void connect(BluetoothDevice device) {
            if (mState == STATE_CONNECTING) {
                if (mConnectThread != null) {
                    mConnectThread.cancel();
                    mConnectThread = null;
                }
            }
            if (mConnectedThread != null) {
                mConnectedThread.cancel();
                mConnectedThread = null;
            }
            mConnectThread = new ConnectThread(device);
            mConnectThread.start();
            setState(STATE_CONNECTING);
        }

        /*
            开启一个 ConnectedThread 来管理对应的当前连接。之前先取消任意现存的 mConnectThread 、
            mConnectedThread 、 mAcceptThread 线程,然后开启新 mConnectedThread ,传入当前刚刚接受的
            socket 连接。最后通过 Handler来通知UI连接
         */
        public synchronized void connected(BluetoothSocket socket, BluetoothDevice device) {
            if (mConnectThread != null) {
                mConnectThread.cancel();
                mConnectThread = null;
            }
            if (mConnectedThread != null) {
                mConnectedThread.cancel();
                mConnectedThread = null;
            }
            if (mAcceptThread != null) {
                mAcceptThread.cancel();
                mAcceptThread = null;
            }
            mConnectedThread = new ConnectedThread(socket);
            mConnectedThread.start();
            Message msg = mHandler.obtainMessage(weixinFragment.MESSAGE_DEVICE_NAME);
            Bundle bundle = new Bundle();
            bundle.putString(weixinFragment.DEVICE_NAME, device.getName());
            msg.setData(bundle);
            mHandler.sendMessage(msg);
            setState(STATE_CONNECTED);
        }

        // 停止所有相关线程,设当前状态为 NONE
        public synchronized void stop() {
            if (mConnectThread != null) {
                mConnectThread.cancel();
                mConnectThread = null;
            }
            if (mConnectedThread != null) {
                mConnectedThread.cancel();
                mConnectedThread = null;
            }
            if (mAcceptThread != null) {
                mAcceptThread.cancel();
                mAcceptThread = null;
            }
            setState(STATE_NONE);
        }

        // 在 STATE_CONNECTED 状态下,调用 mConnectedThread 里的 write 方法,写入 byte
        public void write(byte[] out) {
            ConnectedThread r;
            synchronized (this) {
                if (mState != STATE_CONNECTED)
                    return;
                r = mConnectedThread;
            }
            r.write(out);
        }

        // 连接失败的时候处理,通知 ui ,并设为 STATE_LISTEN 状态
        private void connectionFailed() {
            setState(STATE_LISTEN);
            Message msg = mHandler.obtainMessage(weixinFragment.MESSAGE_TOAST);
            Bundle bundle = new Bundle();
            bundle.putString(weixinFragment.TOAST, "链接不到设备");
            msg.setData(bundle);
            mHandler.sendMessage(msg);
        }

        // 当连接失去的时候,设为 STATE_LISTEN 状态并通知 ui
        private void connectionLost() {
            setState(STATE_LISTEN);
            Message msg = mHandler.obtainMessage(weixinFragment.MESSAGE_TOAST);
            Bundle bundle = new Bundle();
            bundle.putString(weixinFragment.TOAST, "设备链接中断");
            msg.setData(bundle);
            mHandler.sendMessage(msg);
        }
// 创建监听线程,准备接受新连接。使用阻塞方式,调用 BluetoothServerSocket.accept()
        private class AcceptThread extends Thread {
            private final BluetoothServerSocket mmServerSocket;

            public AcceptThread() {
                BluetoothServerSocket tmp = null;
                try {
                    //使用射频端口(RF comm)监听
                    tmp = mAdapter.listenUsingRfcommWithServiceRecord(NAME, MY_UUID);
                } catch (IOException e) {
                }
                mmServerSocket = tmp;
            }
/*
            连接线程,专门用来对外发出连接对方蓝牙的请求和处理流程。
            构造函数里通过 BluetoothDevice.createRfcommSocketToServiceRecord() ,
            从待连接的 device 产生 BluetoothSocket. 然后在 run 方法中 connect ,
            成功后调用 BluetoothChatSevice 的 connected() 方法。定义 cancel() 在关闭线程时能够关闭相关socket 。
*/
        private class ConnectThread extends Thread {
            private final BluetoothSocket mmSocket;
            private final BluetoothDevice mmDevice;

            public ConnectThread(BluetoothDevice device) {
                mmDevice = device;
                BluetoothSocket tmp = null;
                try {
                    tmp = device.createRfcommSocketToServiceRecord(MY_UUID);
                } catch (IOException e) {
                    e.printStackTrace();
                }
                mmSocket = tmp;
            }
/*
            双方蓝牙连接后一直运行的线程;构造函数中设置输入输出流。
            run()方法中使用阻塞模式的 InputStream.read()循环读取输入流,然后发送到 UI 线程中更新聊天消息。
            本线程也提供了 write() 将聊天消息写入输出流传输至对方,传输成功后回写入 UI 线程。最后使用cancel()关闭连接的 socket
*/
        private class ConnectedThread extends Thread {
            private final BluetoothSocket mmSocket;
            private final InputStream mmInStream;
            private final OutputStream mmOutStream;

            public ConnectedThread(BluetoothSocket socket) {
                mmSocket = socket;
                InputStream tmpIn = null;
                OutputStream tmpOut = null;
                try {
                    tmpIn = socket.getInputStream();
                    tmpOut = socket.getOutputStream();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                mmInStream = tmpIn;
                mmOutStream = tmpOut;
            }

DeviceList.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <TextView android:id="@+id/title_paired_devices"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/title_paired_devices"
        android:visibility="gone"
        android:background="#666"
        android:textColor="#fff"
        android:paddingLeft="5dp" />
    <ListView android:id="@+id/paired_devices"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_weight="1" />
    <TextView android:id="@+id/title_new_devices"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/title_other_devices"
        android:visibility="gone"
        android:background="#666"
        android:textColor="#fff"
        android:paddingLeft="5dp" />
    <!--android:visibility="gone"表示不占空间的隐藏,invisible是占空间-->
    <ListView android:id="@+id/new_devices"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_weight="2" />
    <Button android:id="@+id/button_scan"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/button_scan" />
</LinearLayout>

最后奉上源码:https://github.com/HS-98/MyWeChat.git

已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页