您的位置:首页 > 移动开发 > Android开发

Android BLE与终端通信(四)——实现服务器与客户端即时通讯功能

2016-12-08 16:13 886 查看
标签: androidsocket即时通讯服务器通信
2016-01-27 22:19 2891人阅读 评论(21) 收藏 举报


 分类:

Android(110) 


版权声明:本文为博主原创文章,博客地址:http://blog.csdn.ne
4000
t/qq_26787115,未经博主允许不得转载。

目录(?)[+]


Android BLE与终端通信(四)——实现服务器与客户端即时通讯功能

前面几篇一直在讲一些基础,其实说实话,蓝牙主要为多的还是一些概念性的东西,当你把概念都熟悉了之后,你会很简单的就可以实现一些逻辑,主要是Socket和I/O流的操作,今天就来一起做一个聊天的小程序,我们都知道,我们实现蓝牙连接,蓝牙是有主从关系的,所以有客户端和服务端之分,我们新建一个工程——BLE_QQ(hh,毕竟是即时通讯嘛,和QQ挨个边)

参考Google的API:http://developer.android.com/guide/topics/connectivity/bluetooth.html



在开始之前,别忘了添加权限

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

一.OpenBluetooth

Google的API上说的是十分的清楚,我们作为初学者要把他当做说明书一样来看待



这样的话,我们就来实现打开蓝牙并且打开可见性,可见性默认是120s,MAX为3600s,这里在强调一遍,打开蓝牙有两种方式,一种是弹框提示,一种是强制打开,这在之前也是提过好多次了的

/**
* 打开蓝牙并且搜索
*/
public void openBluetooth(View v) {
// 开启搜索
Intent discoverableIntent = new Intent(
BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
// 设置可见性300s
discoverableIntent.putExtra(
BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);
startActivity(discoverableIntent);

// 强制打开
// mBluetoothAdapter.enable();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

CloseBluetooth

关闭蓝牙也就直接调用BluetoothAdapter的disable()方法;

/**
* 关闭蓝牙
*/
public void closeBluetooth(View v) {
mBluetoothAdapter.disable();
}
1
2
3
4
5
6
7
1
2
3
4
5
6
7

客户端

我们在MainActivity中写一个button直接跳转到ClientActivity中去

/**
* 打开客户端
*/
public void Client(View v) {
startActivity(new Intent(this, ClientActivity.class));
}
1
2
3
4
5
6
1
2
3
4
5
6

ClientActivity

package com.example.ble_qq;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.SocketOptions;
import java.util.UUID;

import com.example.ble_qq.ServiceActivity.ReceiverInfoThread;

import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothServerSocket;
import android.bluetooth.BluetoothSocket;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

/**
* 客户端
*
* @author LGL
*
*/
public class ClientActivity extends Activity {

// 连接成功
private static final int CONN_SUCCESS = 0x1;
// 连接失败
private static final int CONN_FAIL = 0x2;
private static final int RECEIVER_INFO = 0x3;
// 设置文本框为空
private static final int SET_EDITTEXT_NULL = 0x4;
// 接收到的消息
private TextView tv_content;
// 输入框
private EditText et_info;

// 发送按钮
private Button btn_send;

// 本地蓝牙适配器
private BluetoothAdapter mBluetoothAdapter = null;

// 远程设备
private BluetoothDevice device = null;

// 蓝牙设备Socket客户端
private BluetoothSocket socket = null;

private boolean isReceiver = true;

// 设备名称
private static final String NAME = "LGL";

// 输入输出流
private PrintStream out;
private BufferedReader in;

@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setTitle("客户端");
setContentView(R.layout.activity_client);

initView();
// 初始化Socket客户端连接
init();

}

private void initView() {
// 初始化
tv_content = (TextView) findViewById(R.id.tv_content);
et_info = (EditText) findViewById(R.id.et_info);
btn_send = (Button) findViewById(R.id.btn_send);
}

private void init() {
tv_content.setText("客户端已经启动,正在与服务端连接...\n");
// 开始连接
new Thread(new Runnable() {

@Override
public void run() {

try {
// 得到本地蓝牙适配器
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
// 通过本地适配器得到地址,这个地址可以公共扫描来获取,就是getAddress()返回的地址
device = mBluetoothAdapter
.getRemoteDevice("98:6C:F5:CE:0E:81");
// 根据UUID返回一个socket,要与服务器的UUID一致
socket = device.createRfcommSocketToServiceRecord(UUID
.fromString("00000000-2527-eef3-ffff-ffffe3160865"));
if (socket != null) {
// 连接
socket.connect();
// 处理流
out = new PrintStream(socket.getOutputStream());

in = new BufferedReader(new InputStreamReader(socket
.getInputStream()));
}
// 连接成功发送handler
handler.sendEmptyMessage(CONN_SUCCESS);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
Message mes = handler.obtainMessage(CONN_FAIL,
e.getLocalizedMessage());
handler.sendMessage(mes);
}

}
}).start();
}

/**
* Handler接收消息
*
*/
private Handler handler = new Handler() {
public void handleMessage(Message msg) {
switch (msg.what) {
case CONN_SUCCESS:
setInfo("连接成功! \n");
btn_send.setEnabled(true);
Log.i("设备的名称", device.getName());
Log.i("设备的UUID", device.getUuids() + "");
Log.i("设备的地址", device.getAddress());
// 开始接收信息
new Thread(new ReceiverInfoThread()).start();
break;
case CONN_FAIL:
setInfo("连接失败! \n");
setInfo(msg.obj.toString() + "\n");
break;
case RECEIVER_INFO:
setInfo(msg.obj.toString() + "\n");
break;
case SET_EDITTEXT_NULL:
et_info.setText("");
break;

}
}
};

/**
* 接收消息的线程
*/
class ReceiverInfoThread implements Runnable {

@Override
public void run() {
String info = null;
while (isReceiver) {
try {
info = in.readLine();
Message msg = handler.obtainMessage(RECEIVER_INFO);
handler.sendMessage(msg);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}

/**
* 发送消息
*/
public void SendText(View v) {
final String text = et_info.getText().toString();
// 不能为空
if (!TextUtils.isEmpty(text)) {
Toast.makeText(this, "不能为空", Toast.LENGTH_SHORT).show();
}
new Thread(new Runnable() {

@Override
public void run() {
// 输出
out.println(text);
out.flush();
// 把文本框设置为空
handler.sendEmptyMessage(SET_EDITTEXT_NULL);
}
}).start();
}

/**
* 拼接文本信息
*/
private void setInfo(String info) {
StringBuffer sb = new StringBuffer();
sb.append(tv_content.getText());
sb.append(info);
tv_content.setText(sb);
}
}
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
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

服务端

我们在MainActivity中写一个button直接跳转到ServiceActivity中去

/**
* 打开服务端
*/
public void Service(View v) {
startActivity(new Intent(this, ServiceActivity.class));
}
1
2
3
4
5
6
1
2
3
4
5
6

ServiceActivity

package com.example.ble_qq;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.util.UUID;

import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothServerSocket;
import android.bluetooth.BluetoothSocket;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.text.TextUtils;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

/**
* 服务端
*
* @author LGL
*
*/
public class ServiceActivity extends Activity {

// 连接成功
private static final int CONN_SUCCESS = 0x1;
// 连接失败
private static final int CONN_FAIL = 0x2;
private static final int RECEIVER_INFO = 0x3;
// 设置文本框为空
private static final int SET_EDITTEXT_NULL = 0x4;
// 接收到的消息
private TextView tv_content;
// 输入框
private EditText et_info;

// 发送按钮
private Button btn_send;

// 本地蓝牙适配器
private BluetoothAdapter mBluetoothAdapter = null;

// 蓝牙设备Socket服务端
private BluetoothServerSocket serviceSocket = null;

// 蓝牙设备Socket客户端
private BluetoothSocket socket = null;

// 设备名称‘
private static final String NAME = "LGL";

private boolean isReceiver = true;

// 输入输出流
private PrintStream out;
private BufferedReader in;

@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setTitle("服务端");
setContentView(R.layout.activity_service);

initView();
// 创建蓝牙服务端的Socket
initService();
}

private void initView() {
// 初始化
tv_content = (TextView) findViewById(R.id.tv_content);
et_info = (EditText) findViewById(R.id.et_info);
btn_send = (Button) findViewById(R.id.btn_send);

}

private void initService() {
tv_content.setText("服务器已经启动,正在等待设备连接...\n");
// 开启线程操作
new Thread(new Runnable() {

@Override
public void run() {
// 得到本地适配器
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
// 创建蓝牙Socket服务端
try {
// 服务端地址
serviceSocket = mBluetoothAdapter
.listenUsingInsecureRfcommWithServiceRecord(
NAME,
UUID.fromString("00000000-2527-eef3-ffff-ffffe3160865"));
// 阻塞线程等待连接
socket = serviceSocket.accept();
if (socket != null) {
// I/O流
out = new PrintStream(socket.getOutputStream());

in = new BufferedReader(new InputStreamReader(socket
.getInputStream()));
}
// 连接成功发送handler
handler.sendEmptyMessage(CONN_SUCCESS);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
Message mes = handler.obtainMessage(CONN_FAIL,
e.getLocalizedMessage());
handler.sendMessage(mes);
}

}
}).start();
}

/**
* Handler接收消息
*
*/
private Handler handler = new Handler() {
public void handleMessage(Message msg) {
switch (msg.what) {
case CONN_SUCCESS:
setInfo("连接成功! \n");
btn_send.setEnabled(true);
new Thread(new ReceiverInfoThread()).start();
break;
case CONN_FAIL:
setInfo("连接失败! \n");
setInfo(msg.obj.toString() + "\n");
break;
case RECEIVER_INFO:
setInfo(msg.obj.toString() + "\n");
break;
case SET_EDITTEXT_NULL:
et_info.setText("");
break;

}
}
};

/**
* 接收消息的线程
*/
class ReceiverInfoThread implements Runnable {

@Override
public void run() {
String info = null;
while (isReceiver) {
try {
info = in.readLine();
Message msg = handler.obtainMessage(RECEIVER_INFO);
handler.sendMessage(msg);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}

/**
* 发送消息
*/
public void SendText(View v) {
final String text = et_info.getText().toString();
// 不能为空
if (!TextUtils.isEmpty(text)) {
Toast.makeText(this, "不能为空", Toast.LENGTH_SHORT).show();
}
new Thread(new Runnable() {

@Override
public void run() {
// 输出
out.println(text);
out.flush();
// 把文本框设置为空
handler.sendEmptyMessage(SET_EDITTEXT_NULL);
}
}).start();
}

/**
* 拼接文本信息
*/
private void setInfo(String info) {
StringBuffer sb = new StringBuffer();
sb.append(tv_content.getText());
sb.append(info);
tv_content.setText(sb);
}
}
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
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

XML

<?xml version="1.0" encoding="utf-8"?>
<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/tv_content"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />

<EditText
android:id="@+id/et_info"
android:layout_width="match_parent"
android:layout_height="wrap_content" />

<Button
android:id="@+id/btn_send"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="SendText"
android:text="发送" />

</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
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

实际上运行结果是这样的,我们必须准备两部手机,然后先用蓝牙配对,在进行连接





这样我们两个设备就配对成功了


Demo下载地址:http://download.csdn.net/detail/qq_26787115/9420355

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐