刚好碰到这蓝牙通信方面的项目,上网也看过其他人在蓝牙这方面写的博客,但大多都不全,给一些初触蓝牙的开发者造成一定的麻烦,自己当初也费了不少劲。所以把自己参考网上的一些资料用Android studio写的代码完全放出来,分享一下。菜鸟初写博客,若有不恰之处,请指出,必改正。下面我会把自己的思路和代码一一呈现。(PS:由于后期做了些逻辑操作,代码可能有点臃肿,请勿怪。还好完整的代码是会有的,里面有多出来的一两个类没有用的,但懒得重新打包了)
第一篇博客写完,感觉好菜。资源下载:http://download.csdn.net/detail/u013168302/9146907
1.添加权限
2.成员变量跟onCreate()方法,为了方便阅读,把这些摆出来
public class PipelineActivity extends Activity {
public static BluetoothSocket btSocket;
private BluetoothAdapter bluetoothAdapter;
private ArrayAdapter deviceAdapter;
private List listDevices;
private ListView listView;
private LinearLayout btContent;
private TextView btAllData;
private Button openBT;
private Button searchBT;
final private static int MESSAGE_READ = 100;
int i = 0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.pipeline);
listView = (ListView) this.findViewById(R.id.list);
btContent = (LinearLayout) findViewById(R.id.bt_content_llt);
btAllData = (TextView) findViewById(R.id.all_data);
btAllData.setText(btAllData.getText(), TextView.BufferType.EDITABLE);//这行可实现TextView尾部追加http://blog.csdn.net/u013168302/article/details/48785927
openBT = (Button) findViewById(R.id.open_btn);
searchBT = (Button) findViewById(R.id.search_btn);
listDevices = new ArrayList();
bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (bluetoothAdapter.isEnabled()) {
openBT.setText("关闭蓝牙");
}
deviceAdapter = new ArrayAdapter(getApplicationContext(), R.layout.list_item, listDevices);
openBT.setOnClickListener(new BTListener());
searchBT.setOnClickListener(new BTListener());
listView.setAdapter(deviceAdapter);
listView.setOnItemClickListener(new ItemClickListener());//添加监听
}
3.注册广播(因为下面搜索时要用到,所以现在前面注册)
private BroadcastReceiver receiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
//下面几行是为了在logcat里面看到搜索到的设备细节,需要的话,可以将注释打开
// Bundle b = intent.getExtras();
// Object[] lstName = b.keySet().toArray();
// // 显示所有收到的消息及其细节
// for (int i = 0; i < lstName.length; i++) {
// String keyName = lstName[i].toString();
// Log.e("-----" + keyName, String.valueOf(b.get(keyName)));
// }
//搜索设备时,取得设备的MAC地址
if (BluetoothDevice.ACTION_FOUND.equals(action)) {
BluetoothDevice device = intent
.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
String str = device.getName() + "|" + device.getAddress();
if (listDevices.indexOf(str) == -1)// 防止重复添加
listDevices.add(str); // 获取设备名称和mac地址
if (deviceAdapter != null) {
deviceAdapter.notifyDataSetChanged();
}
}
}
};
4.点击开启蓝牙,搜索蓝牙设备。 将搜索到设备名称和mac地址通过BroadcastReceiver保存到list集合,再在listview中展示
/**
* 蓝牙开启与搜索按钮点击监听
*/
class BTListener implements View.OnClickListener {
@Override
public void onClick(View view) {
if (view.getId() == R.id.open_btn) {
if (!bluetoothAdapter.isEnabled()) {
bluetoothAdapter.enable();//开启蓝牙
Intent enable = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
enable.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300); //300秒为蓝牙设备可见时间
startActivity(enable);
openBT.setText("关闭蓝牙");
} else {
bluetoothAdapter.disable();//关闭蓝牙
openBT.setText("开启蓝牙");
if (btSocket != null) {
try {
btSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
} else if (view.getId() == R.id.search_btn) {
if (!bluetoothAdapter.isEnabled()) {
Toast.makeText(getApplicationContext(), "请先开启蓝牙", Toast.LENGTH_SHORT).show();
} else {
btContent.setVisibility(View.GONE);
listView.setVisibility(View.VISIBLE);
if (listDevices != null) {
listDevices.clear();
if (deviceAdapter != null) {
deviceAdapter.notifyDataSetChanged();
}
}
bluetoothAdapter.startDiscovery();
IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
registerReceiver(receiver, filter);
}
}
}
}
5.点击listview的item,通过反射连接设备。连接设备之前需要UUID来配对。查看网上的例子和自己的一些实践发现,通过UUID会出现一些问题,当然也有可能只是我自己的代码有问题。所以在此采取反射来获取蓝牙socket对象。
/**
* 蓝牙选项,listview列表点击监听
*/
class ItemClickListener implements AdapterView.OnItemClickListener {
@Override
public void onItemClick(AdapterView> adapterView, View view, int position, long l) {
if (!bluetoothAdapter.isEnabled()) {
Toast.makeText(getApplicationContext(), "请先开启蓝牙", Toast.LENGTH_SHORT).show();
} else {
bluetoothAdapter.cancelDiscovery();//停止搜索
String str = listDevices.get(position);
String macAdress = str.split("\|")[1];
BluetoothDevice device = bluetoothAdapter.getRemoteDevice(macAdress);
try {
Method clientMethod = device.getClass()
.getMethod("createRfcommSocket", new Class[]{int.class});
btSocket = (BluetoothSocket) clientMethod.invoke(device, 1);
connect(btSocket);//连接设备
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
}
6.连接蓝牙设备,并开辟子线程通信
在这里值得注意while里面的2行代码。这2行代码花了不少功夫才弄到的
(1)if(inputStream.available()
>0==false)
(2)Thread.sleep(400);//等待0.4秒,作用:让数据接收完整
这2行用于处理inputStream读取数据不完整或混乱的问题,但感觉还是不够好。若谁有更好的方法,欢迎提出。
另外inputStream在这里是关不掉的,因为这是蓝牙通信,单片机每产生的数据都要传输到手机端。试过多次:一旦断开inputstream,while循环结束,单片机再次产生的数据无法传送。不知道我有没有弄错,欢迎指出。
/**
* 连接蓝牙及获取数据
*/
public void connect(final BluetoothSocket btSocket) {
try {
btSocket.connect();//连接
if (btSocket.isConnected()) {
Log.e("----connect--- :", "连接成功");
Toast.makeText(getApplicationContext(), "蓝牙连接成功", Toast.LENGTH_SHORT).show();
listView.setVisibility(View.GONE);
btContent.setVisibility(View.VISIBLE);
new ConnetThread().start();//通信
} else {
Toast.makeText(getApplicationContext(), "蓝牙连接失败", Toast.LENGTH_SHORT).show();
btSocket.close();
listView.setVisibility(View.VISIBLE);
btContent.setVisibility(View.GONE);
Log.e("--------- :", "连接关闭");
}
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 蓝牙通信管理
*/
private class ConnetThread extends Thread {
public void run() {
try {
InputStream inputStream = btSocket.getInputStream();
byte[] data = new byte[1024];
int len = 0;
String result = "";
while (len != -1) {
if (inputStream.available() > 0 == false) {//inputStream接收的数据是一段段的,如果不先
continue;
} else {
try {
Thread.sleep(500);//等待0.5秒,让数据接收完整
len = inputStream.read(data);
result = URLDecoder.decode(new String(data, "utf-8"));
// Log.e("----result:----- :", ">>>" + result);
Message msg = new Message();
msg.what = MESSAGE_READ;
msg.obj = result;
handler.sendMessage(msg);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
inputStream.close();//关不了,也好像不能关
Log.e("--------- :", "关闭inputStream");
if (btSocket != null) {
btSocket.close();
}
} catch (IOException e) {
Log.e("TAG", e.toString());
}
}
}
7.用Handler处理Message
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MESSAGE_READ:
String result = (String) msg.obj;
String data = result.split("\r\n")[0];
Log.e("----data:----- :", ">>>" + data);
if (i < 6) {
Editable text = (Editable) btAllData.getText();
text.append(data);
btAllData.setText(text + "
");
i++;
} else {
btAllData.setText(data + "
");
i = 0;
}
break;
}
}
};
@Override
protected void onDestroy() {
unregisterReceiver(receiver);
super.onDestroy();
}
8.1布局文件(尚未优化)
8.2 item布局
8.3 资源文件strings.xml
bluetooth
Hello world!
Settings
管道检测仪
开启蓝牙
关闭蓝牙
搜索蓝牙
全部数据:
#F0F0F0
#A5D8F5
8.4 style
8.5 listview的item选择器