这几天很不顺利,经过一段时间的疯狂加班之后工作终于辞了,淡定下来回顾下最近所开发的软件,当做整合整合知识。闲话不多说进入正题。
随着硬件成本的不断降低,目前越来越多的终端外设也运行了Android系统,因此在和这些外设做短距离的小数据通讯时Android与Android的蓝牙通讯成为了主力军,本次采用的是socket蓝牙通讯,熟悉socket的同学肯定知道,socket通讯肯定就有服务器端和客户端,我们先来介绍服务器的代码:
老样子我们先介绍下界面布局,本服务器端有两个页面,分别是蓝牙配对页面和收发接口页面,如下图:
上图第一个界面是蓝牙的配对界面,打开软件会列出已配对的设备,点击扫面按键会扫描附近的蓝牙设备(如果长时间不能够扫面到设备建议先使用系统进行配对),点击相应的需连接设备后进入第二个界面,等待客户端的连接,具体代码如下:
蓝牙扫描页面:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.viewat.bluetooth.MainActivity" >
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="搜索设备"
android:onClick="onClick_search"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="60dp"
android:text="蓝牙设备列表"
android:layout_centerHorizontal="true"/>
<ListView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="80dp"
android:id="@+id/listView">
</ListView>
</RelativeLayout>
蓝牙收发操作界面:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/white">
<ScrollView
android:layout_width="match_parent"
android:layout_height="300dp"
android:paddingLeft="10dp"
android:paddingRight="10dp">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/tv_message"/>
</ScrollView>
<EditText
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_alignParentBottom="true"
android:layout_marginBottom="80dp"
android:id="@+id/editText"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_marginBottom="20dp"
android:layout_marginLeft="30dp"
android:text="发送"
android:onClick="onClick_send"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_marginBottom="20dp"
android:layout_alignParentRight="true"
android:layout_marginRight="30dp"
android:text="结束回话,断开链接"
android:onClick="onClick_end"/>
</RelativeLayout>
下面介绍实现的代码,首先是获取已配对的蓝牙设备罗列出来:
/**
* 列出所有的蓝牙设备
*/
private void init() {
Log.i("tag", "mBtAdapter=="+ mBtAdapter);
//根据适配器得到所有的设备信息
Set<BluetoothDevice> deviceSet = mBtAdapter.getBondedDevices();
if (deviceSet.size() > 0) {
for (BluetoothDevice device : deviceSet) {
mDatas.add(new DeviceBean(device.getName() + "\n" + device.getAddress(), true));
mAdapter.notifyDataSetChanged();
mListView.setSelection(mDatas.size() - 1);
}
} else {
mDatas.add(new DeviceBean("没有配对的设备", true));
mAdapter.notifyDataSetChanged();
mListView.setSelection(mDatas.size() - 1);
}
}
利用广播获取所有的蓝牙设备:
/**
* 发现设备广播
*/
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (BluetoothDevice.ACTION_FOUND.equals(action)) {
// 获得设备信息
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
// 如果绑定的状态不一样
if (device.getBondState() != BluetoothDevice.BOND_BONDED) {
mDatas.add(new DeviceBean(device.getName() + "\n" + device.getAddress(), false));
mAdapter.notifyDataSetChanged();
mListView.setSelection(mDatas.size() - 1);
}
// 如果搜索完成了
} else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) {
setProgressBarIndeterminateVisibility(false);
if (mListView.getCount() == 0) {
mDatas.add(new DeviceBean("没有发现蓝牙设备", false));
mAdapter.notifyDataSetChanged();
mListView.setSelection(mDatas.size() - 1);
}
showTxt("请重新搜索");
}
}
};
接着监听点击事件,进入连接页面:
/**
* 点击设备监听
*/
private OnItemClickListener mDeviceClickListener = new OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
DeviceBean bean = mDatas.get(position);
String info = bean.message;
String address = info.substring(info.length() - 17);
BlueToothAddress = address;
AlertDialog.Builder stopDialog = new AlertDialog.Builder(MainActivity.this);
stopDialog.setTitle("连接");//标题
stopDialog.setMessage(bean.message);
stopDialog.setPositiveButton("连接", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
mBtAdapter.cancelDiscovery();
// showTxt("停止扫描,进行连接...");
startActivity(new Intent(MainActivity.this,ChatActivity.class));
dialog.cancel();
}
});
stopDialog.setNegativeButton("取消", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
BlueToothAddress = null;
dialog.cancel();
}
});
stopDialog.show();
}
};
紧接着会跳转到蓝牙的收发页面,首先获得一个蓝牙适配器 mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); 接着会打开监听的线程;
// 开启服务器
private class ServerThread extends Thread {
public void run() {
try {
// 创建一个蓝牙服务器 参数分别:服务器名称、UUID
mServerSocket = mBluetoothAdapter.listenUsingRfcommWithServiceRecord(PROTOCOL_SCHEME_RFCOMM,
UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"));
Message msg = new Message();
msg.obj = "请稍候,正在等待客户端的连接...";
msg.what = STATUS_CONNECT;
mHandler.sendMessage(msg);
/* 接受客户端的连接请求 */
mSocket = mServerSocket.accept();
msg = new Message();
msg.obj = "客户端已经连接上!可以发送信息。";
msg.what = STATUS_CONNECT;
mHandler.sendMessage(msg);
// 启动接受数据
mReadThread = new ReadThread();
mReadThread.start();
} catch (Exception e) {
e.printStackTrace();
}
}
};
此时服务端的代码准备完成,下面我们介绍下客户端代码,同样的客户端也是有类似的两个页面,如下图:
当打开服务端的监听后,打开客户端的代码会进入蓝牙配对的界面,点击相应的服务端设备进入蓝牙操作界面,点击open后会进行和服务端连接,连接成功后会进行相应的提醒,此时既可以进行通讯了,具体的界面代码如下:
蓝牙扫面界面:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.viewat.bluetooth.MainActivity" >
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="搜索设备"
android:onClick="onClick_search"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="60dp"
android:text="蓝牙设备列表"
android:layout_centerHorizontal="true"/>
<ListView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="80dp"
android:id="@+id/listView">
</ListView>
</RelativeLayout>
蓝牙收发界面:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.viewat.bluetoothhostclient.MainActivity" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="客户端"
android:layout_centerHorizontal="true"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:text="open"
android:onClick="onClick_open"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_marginTop="20dp"
android:text="send"
android:onClick="onClick_send"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_marginTop="20dp"
android:text="close"
android:onClick="onClick_close"/>
<EditText
android:layout_width="match_parent"
android:layout_height="40dp"
android:layout_marginTop="100dp"
android:id="@+id/editText"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="160dp"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:text="数据"
android:id="@+id/tv_message"/>
</RelativeLayout>
下面介绍客户端的实现,监听蓝牙列表的点击事件和服务端类似,连接服务端时同样先构建一个蓝牙适配器 mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();紧接着以给定的MAC地址去创建一个 BluetoothDevice 类实例 mDevice = mBluetoothAdapter.getRemoteDevice(address);然后开启客户端的连接线程:
// 客户端线程
private class ClientThread extends Thread {
public void run() {
try {
mSocket = mDevice.createRfcommSocketToServiceRecord(UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"));
Message msg = new Message();
msg.obj = "请稍候,正在连接服务器:" + address;
msg.what = STATUS_CONNECT;
mHandler.sendMessage(msg);
mSocket.connect();
msg = new Message();
msg.obj = "已经连接上服务端!可以发送信息。";
msg.what = STATUS_CONNECT;
mHandler.sendMessage(msg);
// 启动接受数据
mReadThread = new ReadThread();
mReadThread.start();
isOpen = true;
} catch (Exception e) {
Message msg = new Message();
msg.obj = "连接服务端异常!请断开连接重新试一试。";
msg.what = STATUS_CONNECT;
mHandler.sendMessage(msg);
}
}
};
在连接线程之后会开启接收数据的线程,然后利用回调显示在界面上:
// 读取数据
private class ReadThread extends Thread {
public void run() {
byte[] buffer = new byte[1024];
int bytes;
InputStream is = null;
try {
is = mSocket.getInputStream();
while (true) {
if ((bytes = is.read(buffer)) > 0) {
byte[] buf_data = new byte[bytes];
for (int i = 0; i < bytes; i++) {
buf_data[i] = buffer[i];
}
String s = new String(buf_data);
Message msg = new Message();
Bundle bundle = msg.getData();
bundle.putString("info", s);
bundle.putByteArray("buf", buf_data);
mHandler.sendMessage(msg);
}
}
} catch (Exception e1) {
e1.printStackTrace();
} finally {
try {
is.close();
} catch (Exception e1) {
e1.printStackTrace();
}
}
}
}
致此整个蓝牙收发的客户端和服务端已经全部写完,这里废话下软件的操作流程:
服务端:
进入主界面后,找到对应的手机的蓝牙mac地址,点击后进入聊天界面。
遇到弹框就点同意。
客户端:
进入主界面后,找到对应的手机的蓝牙mac地址,点击后进入聊天界面。
遇到弹框就点同意。
点击open,然后弹框上点击同意,在服务端上显示"客户端已经连接上,可以发送信息",表示能进行通讯了
最后贴上我的源代码:源码下载(辛苦手打收两个积分,如果积分不够可在下面留下邮箱,我看到后第一时间发送源码)
纯手打,有帮助就回复下,有什么问题也可留言,我们共同讨论下。
转载请注明出处!谢谢!