前面的终究只是小知识点,上不了台面,也只能算是起到一个科普的作用,而同步到实际的开发上去,今天就来延续前两篇实现蓝牙主从关系的客户端和服务端了,本文相关链接需要去google的API上查看,需要翻墙的
Bluetooth Low Energy:http://developer.android.com/guide/topics/connectivity/bluetooth-le.html
但是我们依然没有讲到BLE(低功耗蓝牙),放心,下一篇就回讲到,跟前面的基本上很大的不同,我们今天来看下客户端和服务端的实现
我们以上篇为栗子:
Android BLE与终端通信(二)——Android Bluetooth基础搜索蓝牙设备显示列表
蓝牙数据传输其实跟我们的 Socket(套接字)有点类似,如果有不懂的,可以百度一下概念,我们只要知道是这么回事就可以了,在网络中使用Socket和ServerSocket控制客户端和服务端来数据读写。而蓝牙通讯也是由客户端和服务端来完成的,蓝牙客户端Socket是BluetoothSocket,蓝牙服务端Socket是BluetoothServerSocket,这两个类都在android.bluetooth包下,而且无论是BluetoothSocket还是BluetoothServerSocket,我们都需要一个UUID(标识符),这个UUID在上篇也是有提到,而且他的格式也是固定的:
第一段是8位,中间三段式4位,最后一段是12位,UUID相当于Socket的端口,而蓝牙地址则相当于Socket的IP
<LinearLayout xmlns:android&#61;"http://schemas.android.com/apk/res/android"xmlns:tools&#61;"http://schemas.android.com/tools"android:layout_width&#61;"match_parent"android:layout_height&#61;"match_parent"android:orientation&#61;"vertical" ><Button
android:layout_width&#61;"match_parent"android:layout_height&#61;"wrap_content"android:onClick&#61;"btnSearch"android:text&#61;"搜索蓝牙设备" /><ListView
android:id&#61;"&#64;&#43;id/lvDevices"android:layout_width&#61;"match_parent"android:layout_height&#61;"0dp"android:layout_weight&#61;"1" />LinearLayout>
我们需要的东西
// 本地蓝牙适配器private BluetoothAdapter mBluetoothAdapter;// 列表private ListView lvDevices;// 存储搜索到的蓝牙private List
// 获取本地蓝牙适配器mBluetoothAdapter &#61; BluetoothAdapter.getDefaultAdapter();// 判断手机是否支持蓝牙if (mBluetoothAdapter &#61;&#61; null) {Toast.makeText(this, "设备不支持蓝牙", Toast.LENGTH_SHORT).show();finish();}// 判断是否打开蓝牙if (!mBluetoothAdapter.isEnabled()) {// 弹出对话框提示用户是后打开Intent intent &#61; new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);startActivityForResult(intent, 1);// 不做提示&#xff0c;强行打开// mBluetoothAdapter.enable();}// 初始化listviewlvDevices &#61; (ListView) findViewById(R.id.lvDevices);lvDevices.setOnItemClickListener(this);// 获取已经配对的设备Set
public void btnSearch(View v) {// 设置进度条setProgressBarIndeterminateVisibility(true);setTitle("正在搜索...");// 判断是否在搜索,如果在搜索&#xff0c;就取消搜索if (mBluetoothAdapter.isDiscovering()) {mBluetoothAdapter.cancelDiscovery();}// 开始搜索mBluetoothAdapter.startDiscovery();}
private final BroadcastReceiver receiver &#61; new BroadcastReceiver() {&#64;Overridepublic void onReceive(Context context, Intent intent) {// 收到的广播类型String action &#61; intent.getAction();// 发现设备的广播if (BluetoothDevice.ACTION_FOUND.equals(action)) {// 从intent中获取设备BluetoothDevice device &#61; intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);// 判断是否配对过if (device.getBondState() !&#61; BluetoothDevice.BOND_BONDED) {// 添加到列表bluetoothDevices.add(device.getName() &#43; ":"&#43; device.getAddress() &#43; "\n");arrayAdapter.notifyDataSetChanged();}// 搜索完成} else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) {// 关闭进度条setProgressBarIndeterminateVisibility(true);setTitle("搜索完成&#xff01;");}}};
// 客户端&#64;Overridepublic void onItemClick(AdapterView> parent, View view, int position,long id) {// 先获得蓝牙的地址和设备名String s &#61; arrayAdapter.getItem(position);// 单独解析地址String address &#61; s.substring(s.indexOf(":") &#43; 1).trim();// 主动连接蓝牙try {// 判断是否在搜索,如果在搜索&#xff0c;就取消搜索if (mBluetoothAdapter.isDiscovering()) {mBluetoothAdapter.cancelDiscovery();}try {// 判断是否可以获得if (device &#61;&#61; null) {// 获得远程设备device &#61; mBluetoothAdapter.getRemoteDevice(address);}// 开始连接if (clientSocket &#61;&#61; null) {clientSocket &#61; device.createRfcommSocketToServiceRecord(MY_UUID);// 连接clientSocket.connect();// 获得输出流os &#61; clientSocket.getOutputStream();}} catch (Exception e) {// TODO: handle exception}// 如果成功获得输出流if (os !&#61; null) {os.write("Hello Bluetooth!".getBytes("utf-8"));}} catch (Exception e) {// TODO: handle exception}}
// 服务端&#xff0c;需要监听客户端的线程类private Handler handler &#61; new Handler() {public void handleMessage(android.os.Message msg) {Toast.makeText(MainActivity.this, String.valueOf(msg.obj),Toast.LENGTH_SHORT).show();super.handleMessage(msg);}};
// 线程服务类private class AcceptThread extends Thread {private BluetoothServerSocket serverSocket;private BluetoothSocket socket;// 输入 输出流private OutputStream os;private InputStream is;public AcceptThread() {try {serverSocket &#61; mBluetoothAdapter.listenUsingRfcommWithServiceRecord(NAME, MY_UUID);} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}&#64;Overridepublic void run() {// 截获客户端的蓝牙消息try {socket &#61; serverSocket.accept(); // 如果阻塞了&#xff0c;就会一直停留在这里is &#61; socket.getInputStream();os &#61; socket.getOutputStream();// 不断接收请求,如果客户端没有发送的话还是会阻塞while (true) {// 每次只发送128个字节byte[] buffer &#61; new byte[128];// 读取int count &#61; is.read();// 如果读取到了&#xff0c;我们就发送刚才的那个ToastMessage msg &#61; new Message();msg.obj &#61; new String(buffer, 0, count, "utf-8");handler.sendMessage(msg);}} catch (Exception e) {// TODO: handle exception}}}
首先要声明
//启动服务ac &#61; new AcceptThread();ac.start();
package com.lgl.bluetoothget;import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.UUID;import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothServerSocket;
import android.bluetooth.BluetoothSocket;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;public class MainActivity extends Activity implements OnItemClickListener {// 本地蓝牙适配器private BluetoothAdapter mBluetoothAdapter;// 列表private ListView lvDevices;// 存储搜索到的蓝牙private List
}