简单的android蓝牙通信技术(二)

上一篇中讲到了蓝牙的开启和搜索,这一篇中将讲解蓝牙的连接配对及简单的通信。

本篇主要运用了多线程,I/O输入输出流,Handler等。

Android的蓝牙通信与Socket套接字相似,蓝牙端的监听接口和TCP的端口类似,使用了Socket和ServerSocket类。

蓝牙的服务器端为BluetoothServerSocket。

蓝牙的客户端为BluetoothSocket。

蓝牙的端口是RFCOMM,RFCOMM是一个面向连接,通过蓝牙模块进行的数据流传输方式,也称为串行端口规范(Serial Port  Profile , SPP),为创建一个BluetoothSocket去连接到一个已知的设备,使用BluetoothDevice.createRfcommSocketToServiceRecord(),然后调用connect()方法去尝试连接。

示例效果

发送消息手机

接收消手机


在蓝牙连接通信中,将主要利用三个线程。

服务器端监听线程:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
    private class AcceptThread extends Thread {
        private final BluetoothServerSocket mServerSocket;
        private boolean isCancel = false;

        public AcceptThread() {
            Log.d(TAG, "AcceptThread");
            BluetoothServerSocket tmp = null;
            try {
                //监听RFCOMM
                tmp = mBluetoothAdapter.listenUsingRfcommWithServiceRecord(
                        "Bluetooth_Chat_Room", UUID.fromString(UUID_STR));
            } catch (IOException e) {
            }
            mServerSocket = tmp;
        }

        public void run() {
            BluetoothSocket socket = null;
            while (true) {
                try {
                    // 阻塞等待
                    socket = mServerSocket.accept();
                } catch (IOException e) {
                    if (!isCancel) {
                        try {
                            mServerSocket.close();
                        } catch (IOException e1) {
                        }
                        // 异常结束时,再次监听
                        mAcceptThread = new AcceptThread();
                        mAcceptThread.start();
                    }
                    break;
                }
                if (socket != null) {
                    // 管理已经连接的客户端
                    manageConnectedSocket(socket);
                    try {
                        mServerSocket.close();
                    } catch (IOException e) {
                    }
                    mAcceptThread = null;
                    break;
                }
            }
        }

        public void cancel() {
            try {
                Log.d(TAG, "AcceptThread canceled");
                isCancel = true;
                mServerSocket.close();
                mAcceptThread = null;
                if (mCommThread != null && mCommThread.isAlive()) {
                    mCommThread.cancel();
                }
            } catch (IOException e) {
            }
        }
    }
客户端线程:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
    private class ConnectThread extends Thread {
        private final BluetoothSocket mSocket;
        private final BluetoothDevice mDevice;

        public ConnectThread(BluetoothDevice device) {

            Log.d(TAG, "ConnectThread");    
            BluetoothSocket tmp = null;
            mDevice = device;
            try {
                //创建RFCOMM通道
                tmp = device.createRfcommSocketToServiceRecord(UUID
                        .fromString(UUID_STR));
            } catch (IOException e) {
                Log.d(TAG, "createRfcommSocketToServiceRecord error!");
            }

            mSocket = tmp;
        }

        public BluetoothDevice getDevice() {
            return mDevice;
        }

        public void run() {
            // 取消设备扫描
            mBluetoothAdapter.cancelDiscovery();
            try {
                // 连接远程服务器设备
                mSocket.connect();
            } catch (IOException connectException) {
                Log.e(TAG, "Connect server failed");
                try {
                    mSocket.close();
                } catch (IOException closeException) {
                }
                // 连接服务器失败,则自己作为服务器监听
                mAcceptThread = new AcceptThread();
                mAcceptThread.start();
                return;
            } 
            manageConnectedSocket(mSocket);
        }

        public void cancel() {
            try {
                mSocket.close();
            } catch (IOException e) {
            }
            mConnectThread = null;
        }
    }
连接管理线程,负责通信:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
    private class ConnectedThread extends Thread {
        private final BluetoothSocket mSocket;
        private final InputStream mInStream;
        private final OutputStream mOutStream;
        private BufferedWriter mBw;

        public ConnectedThread(BluetoothSocket socket) {
            Log.d(TAG, "ConnectedThread");
            mSocket = socket;
            InputStream tmpIn = null;
            OutputStream tmpOut = null;
            try {
                tmpIn = socket.getInputStream();
                tmpOut = socket.getOutputStream();
            } catch (IOException e) {
            }
            mInStream = tmpIn;
            mOutStream = tmpOut;
            // 获得远程设备的输出缓存字符流
            mBw = new BufferedWriter(new PrintWriter(mOutStream));
        }

        public OutputStream getOutputStream() {
            return mOutStream;
        }

        public boolean write(String msg) {
            if (msg == null)
                return false;
            try {
                mBw.write(msg + "\n");
                mBw.flush();
                System.out.println("Write:" + msg);
            } catch (IOException e) {
                return false;
            }
            return true;
        }

        public String getRemoteName() {
            return mSocket.getRemoteDevice().getName();
        }

        public void cancel() {
            try {
                mSocket.close();
            } catch (IOException e) {
            }
            mCommThread = null;
        }

        public void run() {
            android.os.Message handlerMsg;
            String buffer = null;
            // 获得远程设备的缓存字符输入流
            BufferedReader br = new BufferedReader(new InputStreamReader(
                    mInStream));

            while (true) {
                try {
                    // 读取远程设备的一行数据
                    buffer = br.readLine();
                    System.out.println("收到:" + buffer);
                    if (buffer == null)
                        continue;
                    // 通过Handler更新到UI上
                    handlerMsg = mHandler.obtainMessage();
                    handlerMsg.what = TASK_RECV_MSG;
                    handlerMsg.obj = buffer;
                    mHandler.sendMessage(handlerMsg);
                } catch (IOException e) {
                    try {
                        mSocket.close();
                    } catch (IOException e1) {
                    }
                    mCommThread = null;
                    break;
                }
            }
        }
    }
建立连接管理线程

1
2
3
4
5
    private void manageConnectedSocket(BluetoothSocket socket) {
        // 启动连接管理线程
        mCommThread = new ConnectedThread(socket);
        mCommThread.start();
    }
整个示例程序

布局文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <TextView
        android:id="@+id/XianShi"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:text="无内容" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal" >

        <EditText
            android:id="@+id/SendText"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1.0"
            android:hint="请输入" />

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:onClick="MySend"
            android:text="发送" />
    </LinearLayout>

    <Button
        android:id="@+id/FindBt"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="搜索" />

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:text="蓝牙列表" />

    <ListView
        android:id="@+id/DeviceList"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" >
    </ListView>

</LinearLayout>
示例源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
public class MainActivity extends Activity {
    //调试时使用
    private static final String TAG = "Main";
    // 使能请求码
    private static final int REQUES_BT_ENABLE_CODE = 0x1002;
    //发送与接收到消息
    public static final int TASK_SEND_MSG = 1;
    public static final int TASK_RECV_MSG = 2;
    // UUID号,表示不同的数据协议
    private final String UUID_STR = "00001101-0000-1000-8000-00805F9B34FB";
    private EditText mET;    //发送消息输入框
    private Button MyScan;   //搜索蓝牙按钮
    private TextView MyMessage;  //显示接收到的消息文本框
    private ListView MyBtList;   //显示搜索到的蓝牙列表

    private BluetoothAdapter mBluetoothAdapter;    //蓝牙适配器
    private BluetoothDevice Selectdevice;          //保存连接的蓝牙地址
    private AcceptThread mAcceptThread;            //作为服务端监听线程
    private ConnectThread mConnectThread;          //作为客服端请求线程
    private ConnectedThread mCommThread;           //连接管理线程,负责通信

    private ArrayAdapter<String> adapter;          //Listview的适配器
    private ArrayList<String> mArrayAdapter = new ArrayList<String>();    //ListView的显示内容
    private ArrayList<BluetoothDevice> mDeviceList = new ArrayList<BluetoothDevice>();  //用于保存搜索到的蓝牙,避免重复添加

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);   //请求滚动条
        setContentView(R.layout.activity_main);
        //注册UI
        mET = (EditText) findViewById(R.id.SendText);
        MyScan = (Button) findViewById(R.id.FindBt);
        MyMessage = (TextView) findViewById(R.id.XianShi);
        MyBtList = (ListView) findViewById(R.id.DeviceList);
        //适配ListView
        adapter = new ArrayAdapter<String>(this,
                android.R.layout.simple_list_item_1, mArrayAdapter);
        MyBtList.setAdapter(adapter);
        openBtDevice();
        MyScan.setOnClickListener(new MyScanClick());  //搜索按钮监听
        MyBtList.setOnItemClickListener(new MyBtConnect());  //ListView中蓝牙选择连接监听

        IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
        filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
        // 动态注册广播接收器
        // 用来接收扫描到的设备信息
        registerReceiver(mReceiver, filter);
    }
    //ListView中蓝牙选择连接监听事件
    private class MyBtConnect implements OnItemClickListener {

        @Override
        public void onItemClick(AdapterView<?> parent, View view, int position,
                long id) {
            String s = adapter.getItem(position);    //获取位置
            String address = s.substring(s.indexOf("\n") + 1).trim();  //获取蓝牙地址
            Selectdevice = mBluetoothAdapter.getRemoteDevice(address);  //获得远程设备
            mConnectThread = new ConnectThread(Selectdevice);           //建立客户端线程
            mConnectThread.start();
        }

    }
    //搜索蓝牙监听事件
    private class MyScanClick implements OnClickListener {

        @Override
        public void onClick(View v) {
            // 蓝牙没有正在搜索
            if (!mBluetoothAdapter.isDiscovering()) {
                //服务器端线程未建立或蓝牙未开启
                if (mAcceptThread == null) {
                    openBtDevice();   //开启蓝牙或建立服务器端线程
                    return;
                }
                findBtDevice();     //显示已配对蓝牙
                mBluetoothAdapter.startDiscovery();  //开始搜索
                setProgressBarIndeterminateVisibility(true);  //显示滚动条
            }
        }
    }
    //广播实时更新搜索到蓝牙
    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {

        @Override
        public void onReceive(Context context, Intent intent) {
            // TODO Auto-generated method stub
            String action = intent.getAction();
            if (BluetoothDevice.ACTION_FOUND.equals(action)) {
                BluetoothDevice device = intent
                        .getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                if (mDeviceList.contains(device)) {
                    return;
                }
                mArrayAdapter
                        .add(device.getName() + "\n" + device.getAddress());
                mDeviceList.add(device);
                adapter.notifyDataSetChanged();
            } else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED
                    .equals(action)) {
                setProgressBarIndeterminateVisibility(false);  //搜索结束,关闭滚动条
            }
        }
    };
   //显示已配对蓝牙
    private void findBtDevice() {
        Set<BluetoothDevice> pairedDevices = mBluetoothAdapter
                .getBondedDevices();
        if (pairedDevices.size() > 0) {
            for (BluetoothDevice device : pairedDevices) {
                if (mDeviceList.contains(device)) {
                    return;
                }
                mArrayAdapter
                        .add(device.getName() + "\n" + device.getAddress());
                mDeviceList.add(device);
            }
        }
        adapter.notifyDataSetChanged();
    }
    //打开蓝牙,启动启动服务器端线程
    private boolean openBtDevice() {
        // 获得蓝牙匹配器
        mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
        // 蓝牙设备不被支持
        if (mBluetoothAdapter == null) {
            Log.e(TAG, "Your device is not support Bluetooth!");
            Toast.makeText(this, "该设备没有蓝牙设备", Toast.LENGTH_LONG).show();
            return false;
        }

        // 使能蓝牙设备
        if (!mBluetoothAdapter.isEnabled()) {
            // 隐式Intent
            Intent enableBtIntent = new Intent(
                    BluetoothAdapter.ACTION_REQUEST_ENABLE);
            startActivityForResult(enableBtIntent, REQUES_BT_ENABLE_CODE);
        } else {
            // 如果蓝牙设备已经使能,直接启动服务器端线程
            mAcceptThread = new AcceptThread();
            mAcceptThread.start();
        }
        return true;
    }

    // 当startActivityForResult启动的 画面结束的时候,该方法被回调
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        //
        if (requestCode == REQUES_BT_ENABLE_CODE && resultCode == RESULT_OK) {
            // 直接启动服务器端线程
            mAcceptThread = new AcceptThread();
            mAcceptThread.start();
        }
    }
    //服务端监听线程
    private class AcceptThread extends Thread {
        private final BluetoothServerSocket mServerSocket;
        private boolean isCancel = false;

        public AcceptThread() {
            Log.d(TAG, "AcceptThread");
            BluetoothServerSocket tmp = null;
            try {
                //监听RFCOMM
                tmp = mBluetoothAdapter.listenUsingRfcommWithServiceRecord(
                        "Bluetooth_Chat_Room", UUID.fromString(UUID_STR));
            } catch (IOException e) {
            }
            mServerSocket = tmp;
        }

        public void run() {
            BluetoothSocket socket = null;
            while (true) {
                try {
                    // 阻塞等待
                    socket = mServerSocket.accept();
                } catch (IOException e) {
                    if (!isCancel) {
                        try {
                            mServerSocket.close();
                        } catch (IOException e1) {
                        }
                        // 异常结束时,再次监听
                        mAcceptThread = new AcceptThread();
                        mAcceptThread.start();
                    }
                    break;
                }
                if (socket != null) {
                    // 管理已经连接的客户端
                    manageConnectedSocket(socket);
                    try {
                        mServerSocket.close();
                    } catch (IOException e) {
                    }
                    mAcceptThread = null;
                    break;
                }
            }
        }

        public void cancel() {
            try {
                Log.d(TAG, "AcceptThread canceled");
                isCancel = true;
                mServerSocket.close();
                mAcceptThread = null;
                if (mCommThread != null && mCommThread.isAlive()) {
                    mCommThread.cancel();
                }
            } catch (IOException e) {
            }
        }
    }
    //客户端线程
    private class ConnectThread extends Thread {
        private final BluetoothSocket mSocket;
        private final BluetoothDevice mDevice;

        public ConnectThread(BluetoothDevice device) {

            Log.d(TAG, "ConnectThread");    
            BluetoothSocket tmp = null;
            mDevice = device;
            try {
                //创建RFCOMM通道
                tmp = device.createRfcommSocketToServiceRecord(UUID
                        .fromString(UUID_STR));
            } catch (IOException e) {
                Log.d(TAG, "createRfcommSocketToServiceRecord error!");
            }

            mSocket = tmp;
        }

        public BluetoothDevice getDevice() {
            return mDevice;
        }

        public void run() {
            // 取消设备扫描
            mBluetoothAdapter.cancelDiscovery();
            try {
                // 连接远程服务器设备
                mSocket.connect();
            } catch (IOException connectException) {
                Log.e(TAG, "Connect server failed");
                try {
                    mSocket.close();
                } catch (IOException closeException) {
                }
                // 连接服务器失败,则自己作为服务器监听
                mAcceptThread = new AcceptThread();
                mAcceptThread.start();
                return;
            } 
            manageConnectedSocket(mSocket);
        }

        public void cancel() {
            try {
                mSocket.close();
            } catch (IOException e) {
            }
            mConnectThread = null;
        }
    }
    //连接管理线程,负责通信
    private class ConnectedThread extends Thread {
        private final BluetoothSocket mSocket;
        private final InputStream mInStream;
        private final OutputStream mOutStream;
        private BufferedWriter mBw;

        public ConnectedThread(BluetoothSocket socket) {
            Log.d(TAG, "ConnectedThread");
            mSocket = socket;
            InputStream tmpIn = null;
            OutputStream tmpOut = null;
            try {
                tmpIn = socket.getInputStream();
                tmpOut = socket.getOutputStream();
            } catch (IOException e) {
            }
            mInStream = tmpIn;
            mOutStream = tmpOut;
            // 获得远程设备的输出缓存字符流
            mBw = new BufferedWriter(new PrintWriter(mOutStream));
        }

        public OutputStream getOutputStream() {
            return mOutStream;
        }

        public boolean write(String msg) {
            if (msg == null)
                return false;
            try {
                mBw.write(msg + "\n");
                mBw.flush();
                System.out.println("Write:" + msg);
            } catch (IOException e) {
                return false;
            }
            return true;
        }

        public String getRemoteName() {
            return mSocket.getRemoteDevice().getName();
        }

        public void cancel() {
            try {
                mSocket.close();
            } catch (IOException e) {
            }
            mCommThread = null;
        }

        public void run() {
            android.os.Message handlerMsg;
            String buffer = null;
            // 获得远程设备的缓存字符输入流
            BufferedReader br = new BufferedReader(new InputStreamReader(
                    mInStream));

            while (true) {
                try {
                    // 读取远程设备的一行数据
                    buffer = br.readLine();
                    System.out.println("收到:" + buffer);
                    if (buffer == null)
                        continue;
                    // 通过Handler更新到UI上
                    handlerMsg = mHandler.obtainMessage();
                    handlerMsg.what = TASK_RECV_MSG;
                    handlerMsg.obj = buffer;
                    mHandler.sendMessage(handlerMsg);
                } catch (IOException e) {
                    try {
                        mSocket.close();
                    } catch (IOException e1) {
                    }
                    mCommThread = null;
                    break;
                }
            }
        }
    }
   
    private void manageConnectedSocket(BluetoothSocket socket) {
        // 启动连接管理线程
        mCommThread = new ConnectedThread(socket);
        mCommThread.start();
    }
    //发送消息按钮事件
    public void MySend(View v) {
        String msg = mET.getText().toString().trim();
        if (msg.length() <= 0) {
            Toast.makeText(this, "消息不能为空", Toast.LENGTH_SHORT).show();
            return;
        }
        mCommThread.write(msg);
        android.os.Message SendMsg = new Message();
        SendMsg = mHandler.obtainMessage();
        SendMsg.what = TASK_SEND_MSG;
        SendMsg.obj = msg;
        mHandler.sendMessage(SendMsg);
        mET.setText("");
    }
    //Handler,负责将通信的信息更新到UI上显示
    private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
            case TASK_SEND_MSG:
                Toast.makeText(MainActivity.this, msg.obj.toString(),
                        Toast.LENGTH_SHORT).show();
                break;
            case TASK_RECV_MSG:
                // 获得远程设备发送的消息
                MyMessage.setText(msg.obj.toString());
                break;
            }
        }
    };
}

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值