蓝牙是什么(Bluetooth):
- 一种短距离无线通信技术
- 爱立信公司创建
- 如今由蓝牙技术联盟(Bluetooth Special Interest Group,简称SIG)管理。
- 现在用的都是低功耗蓝牙 Android 4.3(API Level 18)开始引入Bluetooth Low Energy(BLE,低功耗蓝牙)
- 在 5.0 以后才支持外设模式,
无线通信方案:
- NFC 一个近距离接触连接的通信技术 如把手机当公交卡用 消耗最低
- 蓝牙 一种短距离无线通信技术
- WIFI 。。。
为什么要用蓝牙:
- 低功率 便于电池供电设备工作
- 使用方便,点对点连接
- 短距离,低成本,以及高速
- 在智能设备的普及性高,应用广。
理论没有详细了解 这里贴出网址有兴趣可以去看下
UUID:全局唯一标识
- UUID是根据一定算法,计算得到的一长串数字,这个数字的产生使用了多种元素,所以使得这串数字不会重复,每次生成都会产生不一样的序列,所以可以用来作为唯一标识。
- 创建服务器端和客户端时都需要用UUID来创建 连接通讯时只有一样的才可以成功连接上
- 可以代码生成 也可以用uuid生成器
UUID.randomUUID().toString().replace("-", "");
蓝牙通信的流程:
- 注册适配器打开蓝牙
- 注册广播监听蓝牙状态
- 搜索附近设备和已配对设备
- 选择未配对设备进行配对
- 选择已配对设备进行连接通信
1、打开蓝牙:
首先呢 先加权限 获取位置的权限属于高危权限 所以还需要动态调用:
1、AndroidManifest.xml <6.0定位权限那别人都说只加一个就好了 我的貌似不行 所以我就都加上了>
-
<!-- 蓝牙通讯权限 -->
-
<uses-permission android:name="android.permission.BLUETOOTH" />//一些配置连接蓝牙的权限
-
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />//进行操作的权限
-
<!-- 6.0以上需要的权限 -->
-
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
-
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
2、activity
检测位置权限有没有同意 没有的话无法进行附近搜索 所以直接退出应用
-
@RequiresApi(api = Build.VERSION_CODES.M)
-
@Override
-
protected void onResume() {
-
super.onResume();
-
//动态获取权限
-
checkBluetoothAndLocationPermission();
-
}
-
@RequiresApi(api = Build.VERSION_CODES.M)
-
private void checkBluetoothAndLocationPermission() {
-
//判断是否有访问位置的权限,没有权限,直接申请位置权限
-
if ((checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED)
-
|| (checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED)) {
-
requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION,
-
Manifest.permission.ACCESS_FINE_LOCATION}, 2);
-
}
-
}
-
@Override
-
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
-
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
-
switch (requestCode) {
-
case 2:
-
//再次判断是否获取到权限 没有就关闭当前界面
-
for (int i : grantResults) {
-
if (i != PackageManager.PERMISSION_GRANTED) {
-
Toast.makeText(this, "Permission error !!!", Toast.LENGTH_SHORT).show();
-
finish();
-
}
-
}
-
break;
-
}
-
}
在onCreate()方法里,获取蓝牙适配器
BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
BluetoothAdapter这个类常用的方法有:
- getDefaultAdapter: 获取本地的蓝牙适配器
- enable(); 打开蓝牙(不带提示框 但是手机有自带的。。。)
- disable(); 关闭蓝牙
- isEnabled(): 本地蓝牙是否打开
- getAddress(); 获取自己的蓝牙MAC地址
- cancelDiscovery() 停止扫描
- isDiscovering() 是否正在处于扫描过程中
- getState():获取本地蓝牙适配器的状态
- getScanMode(): 获取本地蓝牙适配器的当前蓝牙扫描模式。
打开蓝牙的两种方式:
- 第一种打开方法: 调用enable
- 第二种打开方法 ,调用系统API去打开蓝牙
mBluetoothAdapter.enable();
//不会自动提示用户默认打开 有的手机还是会提示的
Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(intent, REQUEST_OPEN_BT_CODE); //CODE值只是标记可以更改
//会以Dialog样式显示一个Activity , 我们可以在onActivityResult()方法去处理返回值
接下来为了保险起见先判断设备是否支持蓝牙:
-
if(mBluetoothAdapter == null){
-
Toast.makeText(this,"本地蓝牙不可用",Toast.LENGTH_SHORT).show();
-
finish(); //退出应用
-
}
确认支持蓝牙的话就可以调用蓝牙适配器的方法了:
-
String Address = bluetoothAdapter.getAddress(); //获取本机蓝牙MAC地址
-
String Name = bluetoothAdapter.getName(); //获取本机蓝牙名称
-
// 若蓝牙没打开
-
if(!bluetoothAdapter.isEnabled()){
-
bluetoothAdapter.enable(); //打开蓝牙
-
}
上边这些除了 打开蓝牙其他的并没有什么用处 这里只是举个例子
设置可以被搜索到
-
//设置可以被搜索到
-
//判断蓝牙适配器的当前蓝牙扫描模式
-
if (mBluetoothAdapter.getScanMode() != BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE)
-
{
-
Intent discoverableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
-
// 设置被发现时间,最大值是3600秒,0表示设备总是可以被发现的(小于0或者大于3600则会被自动设置为120秒)
-
discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 120);
-
startActivity(discoverableIntent);
-
}
接下来开始搜索附近:
判断是否正在搜索 如果是就停止搜索之类的
-
if (!mBluetoothAdapter.isDiscovering()) {//判断是否正在搜索
-
mBluetoothAdapter.startDiscovery();//开始搜索附近设备
-
textView2.setText("正在搜索...");
-
} else {
-
mBluetoothAdapter.cancelDiscovery();//停止搜索
-
}
搜索附近需要先注册个广播来监听查询附近蓝牙设备:
蓝牙扫描时,扫描到任一远程蓝牙设备时,会发送此广播。两种广播用一个就行
注册分为两种:静态注册和动态注册。
- 静态注册就是在AndroidManifest.xml文件中定义,
- 注册的广播接收器必须继承BroadReceiver 动态注册就是在程序中使用Context.registerReceiver注册。
动态广播
-
//注册广播
-
IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);//搜索到设备
-
registerReceiver(receiver, filter);
-
IntentFilter filter2 = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);//搜索结束
-
registerReceiver(receiver, filter2);
静态广播
-
<!-- 广播接收 -->
-
<receiver android:name="包名.类名" >
-
<intent-filter android:priority="1000">
-
<action android:name="android.bluetooth.adapter.action.DISCOVERY_FINISHED"/>
-
<action android:name="android.bluetooth.device.action.FOUND" />
-
</intent-filter>
-
</receiver>
new个BroadcastReceiver来接收:
广播一旦发送 这边就会调用 onReceive()方法
-
BroadcastReceiver receiver = new BroadcastReceiver() {
-
@Override
-
public void onReceive(Context context, Intent intent) {
-
String action = intent.getAction();
-
if (action.equals(BluetoothDevice.ACTION_FOUND)) {
-
//获取已配对蓝牙设备
-
Set<BluetoothDevice> devices = mBluetoothAdapter.getBondedDevices();
-
for (BluetoothDevice bonddevice : devices) {
-
mPeiDuiList.add(bonddevice);
-
peiDuiAdapter.notifyDataSetChanged();
-
}
-
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
-
//判断未配对的设备
-
if (device.getBondState() != BluetoothDevice.BOND_BONDED) {
-
mFuJinList.add(device);
-
fuJinAdapter.notifyDataSetChanged();
-
}
-
} else if (action.equals(BluetoothAdapter.ACTION_DISCOVERY_FINISHED)) {
-
textView2.setText("搜索完成...");
-
}
-
}
-
};
我这边是创建了两个集合 分别把已配对的和附近的储存进去
-
private ArrayList<BluetoothDevice> mPeiDuiList = new ArrayList<>();
-
private ArrayList<BluetoothDevice> mFuJinList = new ArrayList<>();
接下来把获取到的数据放入适配器显示 这步我就不写了 大家都会
这里用到了蓝牙设备BluetoothDevice
BluetoothDevice用于指代某个蓝牙设备,通常表示对方设备
- getName:获得该设备的名称;
- getAddress:获得该设备的地址;
- createRfcommSocketToServiceRecord:根据UUID创建并返回一个BluetoothSocket。
1 配对
两个设备建立连接以后,就可以进行一个配对的过程。
配对进行的时候,会产生一个密钥用来加密与鉴别连接。一个典型的情况是,从机设备会要求主机设备提供一个密码来完成一个配对过程。
这个密码可以是固定的例如“000000”,也可以是提供给上层的随机产生的一个值。当主机设备发送一个正确的密码是,这两个设备就会相互交换密钥来加密并鉴别连接。
2 绑定
很多情况下,两个设备会需要经常性的断开连接,连接这样的过程,BLE有一个安全功能,允许两台设备配对的时候给对方一个长期的一套安全密钥。
这种机制称作为绑定。允许两个设备再次连接时不需要再次进行配对就能从新加密与鉴别,只要他们存储了这个安全密钥。
配对:
主要写配对和通信 绑定先不多做介绍
-
//点击附近的开始配对
-
mBluetoothAdapter.cancelDiscovery();//停止搜索
-
String address = mFuJinList.get(position).getAddress();
-
Toast.makeText(MainActivity.this, mFuJinList.get(position).getName() + "配对中。。。", Toast.LENGTH_SHORT).show();
-
try {
-
//调用工具类与设备配对
-
//已知自己的地址 点击获取对方的地址 配对
-
remoteDevice = mBluetoothAdapter.getRemoteDevice(address);//通过mac地址获取蓝牙设备
-
ClsUtils.createBond(remoteDevice.getClass(), remoteDevice);
-
} catch (Exception e) {
-
e.printStackTrace();
-
}
这里用到了一个配对工具类ClsUtils
-
package com.example.lin.mylanya.utils;
-
import java.lang.reflect.Field;
-
import java.lang.reflect.Method;
-
import android.bluetooth.BluetoothDevice;
-
import android.util.Log;
-
public class ClsUtils {
-
/**
-
* 与设备配对 参考源码:platform/packages/apps/Settings.git
-
* /Settings/src/com/android/settings/bluetooth/CachedBluetoothDevice.java
-
*/
-
static public boolean createBond(Class btClass,BluetoothDevice btDevice) throws Exception {
-
Method createBondMethod = btClass.getMethod("createBond");
-
Boolean returnValue = (Boolean) createBondMethod.invoke(btDevice);
-
return returnValue.booleanValue();
-
}
-
/**
-
* 与设备解除配对 参考源码:platform/packages/apps/Settings.git
-
* /Settings/src/com/android/settings/bluetooth/CachedBluetoothDevice.java
-
*/
-
static public boolean removeBond(Class btClass,BluetoothDevice btDevice) throws Exception {
-
Method removeBondMethod = btClass.getMethod("removeBond");
-
Boolean returnValue = (Boolean) removeBondMethod.invoke(btDevice);
-
return returnValue.booleanValue();
-
}
-
}
通信:
通信需要创建客户端和服务器来建立连接
通讯是耗时操作所以都用另建了一个类继承Thread来写了
先创建服务器:
服务器一般是在打开蓝牙后创建 这里的ChatController是通信的工具类 这个方法里面调用了服务器线程(AccepThread)的启动方法
-
if (!mBluetoothAdapter.isEnabled()) {//判断蓝牙是否打开
-
mBluetoothAdapter.enable();//打开蓝牙
-
}
-
ChatController.getInstance().waitingForFriends(mBluetoothAdapter, handler);//等待客户端来连接
- 服务器端建立套接字,等待客户端连接,
- 调用BluetoothAdapter的listenUsingRfcommWithServiceRecord方法,产生一个BluetoothServerSocket对象,
- 然后调用BluetoothServerSocket对象的accept方法,
- 注意accept方法会产生阻塞,直到一个客户端连接建立,所以服务器端的socket的建立需要在一个子线程中去做,
AccepThread
-
package com.example.lin.mylanya.utils;
-
import android.bluetooth.BluetoothAdapter;
-
import android.bluetooth.BluetoothServerSocket;
-
import android.bluetooth.BluetoothSocket;
-
import android.os.Handler;
-
import com.example.lin.mylanya.Constant;
-
import java.io.IOException;
-
import java.util.UUID;
-
public class AccepThread extends Thread {
-
/** 连接的名称*/
-
private static final String NAME = "BluetoothClass";
-
/** UUID*/
-
private static final UUID MY_UUID = UUID.fromString(Constant.CONNECTTION_UUID);
-
/** 服务端蓝牙Sokcet*/
-
private final BluetoothServerSocket mmServerSocket;
-
private final BluetoothAdapter mBluetoothAdapter;
-
/** 线程中通信的更新UI的Handler*/
-
private final Handler mHandler;
-
/** 监听到有客户端连接,新建一个线程单独处理,不然在此线程中会堵塞*/
-
private ConnectedThread mConnectedThread;
-
public AccepThread(BluetoothAdapter adapter, Handler handler) throws IOException {
-
mBluetoothAdapter = adapter;
-
this.mHandler = handler;
-
// 获取服务端蓝牙socket
-
mmServerSocket = mBluetoothAdapter.listenUsingRfcommWithServiceRecord(NAME, MY_UUID);
-
}
-
@Override
-
public void run() {
-
super.run();
-
// 连接的客户端soacket
-
BluetoothSocket socket = null;
-
// 服务端是不退出的,要一直监听连接进来的客户端,所以是死循环
-
while (true){
-
try {
-
// 获取连接的客户端socket
-
socket = mmServerSocket.accept();
-
} catch (IOException e) {
-
// 通知主线程更新UI, 获取异常
-
mHandler.sendEmptyMessage(Constant.MSG_ERROR);
-
e.printStackTrace();
-
// 服务端退出一直监听线程
-
break;
-
}
-
if(socket != null) {
-
// 管理连接的客户端socket
-
manageConnectSocket(socket);
-
}
-
}
-
}
-
/**
-
* 管理连接的客户端socket
-
* @param socket
-
*/
-
private void manageConnectSocket(BluetoothSocket socket) {
-
// 只支持同时处理一个连接
-
// mConnectedThread不为空,踢掉之前的客户端
-
if(mConnectedThread != null) {
-
mConnectedThread.cancle();
-
}
-
// 新建一个线程,处理客户端发来的数据
-
mConnectedThread = new ConnectedThread(socket, mHandler);
-
mConnectedThread.start();
-
}
-
/**
-
* 断开服务端,结束监听
-
*/
-
public void cancle() {
-
try {
-
mmServerSocket.close();
-
mHandler.sendEmptyMessage(Constant.MSG_FINISH_LISTENING);
-
} catch (IOException e) {
-
e.printStackTrace();
-
}
-
}
-
/**
-
* 发送数据
-
* @param data
-
*/
-
public void sendData(byte[] data){
-
if(mConnectedThread != null) {
-
mConnectedThread.write(data);
-
}
-
}
-
}
蓝牙服务器套接字BluetoothServiceSocket
- BluetoothServiceSocket是服务端的Socket,用来接收客户端的Socket连接请求
- accept:监听外部的蓝牙连接请求;
- close:关闭服务端的蓝牙监听。
-
当远端设备连接到了的时候,Blueboothserversocket 类将会返回一个 bluetoothsocket。
客户端:
客户端是在点击连接时调用 同上 是不过是调用了客户端线程的启动方法
-
//点击连接
-
String address = mPeiDuiList.get(position).getAddress();
-
String name = mPeiDuiList.get(position).getName();
-
Toast.makeText(MainActivity.this, name + "开始连接 请稍后。。。", Toast.LENGTH_SHORT).show();
-
remoteDevice = mBluetoothAdapter.getRemoteDevice(address);
-
ChatController.getInstance().startChatWith(remoteDevice, mBluetoothAdapter, handler);//与服务器连接进行聊天 也就是客户端连接服务端
- 客户端去连接服务器端,需要先持有服务器端的BluetoothDevice对象,
- 先调用BluetoothDevice的createRfcommSocketToServiceRecord方法,这个方法会产生一个客户端的BluetoothSocket对象,
- 然后调用该对象的connect方法,该过程最好也是单独起一个线程去做
- 创建客户端需要一个UUID
-
package com.example.lin.mylanya.utils;
-
import android.bluetooth.BluetoothAdapter;
-
import android.bluetooth.BluetoothDevice;
-
import android.bluetooth.BluetoothSocket;
-
import android.os.Handler;
-
import com.example.lin.mylanya.Constant;
-
import com.example.lin.mylanya.utils.ConnectedThread;
-
import java.io.IOException;
-
import java.util.UUID;
-
public class ConnectThread extends Thread{
-
private static final UUID MY_UUID = UUID.fromString(Constant.CONNECTTION_UUID);
-
/** 客户端socket*/
-
private final BluetoothSocket mmSoket;
-
/** 要连接的设备*/
-
private final BluetoothDevice mmDevice;
-
private BluetoothAdapter mBluetoothAdapter;
-
/** 主线程通信的Handler*/
-
private final Handler mHandler;
-
/** 发送和接收数据的处理类*/
-
private ConnectedThread mConnectedThread;
-
public ConnectThread(BluetoothDevice device, BluetoothAdapter bluetoothAdapter, Handler mUIhandler) {
-
mmDevice = device;
-
mBluetoothAdapter = bluetoothAdapter;
-
mHandler = mUIhandler;
-
BluetoothSocket tmp = null;
-
try {
-
// 创建客户端Socket
-
tmp = device.createRfcommSocketToServiceRecord(MY_UUID);
-
} catch (IOException e) {
-
e.printStackTrace();
-
}
-
mmSoket = tmp;
-
}
-
@Override
-
public void run() {
-
super.run();
-
// 关闭正在发现设备.(如果此时又在查找设备,又在发送数据,会有冲突,影响传输效率)
-
mBluetoothAdapter.cancelDiscovery();
-
try {
-
// 连接服务器
-
mmSoket.connect();
-
} catch (IOException e) {
-
// 连接异常就关闭
-
try {
-
mmSoket.close();
-
} catch (IOException e1) {
-
}
-
return;
-
}
-
manageConnectedSocket(mmSoket);
-
}
-
private void manageConnectedSocket(BluetoothSocket mmSoket) {
-
// 新建一个线程进行通讯,不然会发现线程堵塞
-
mConnectedThread = new ConnectedThread(mmSoket,mHandler);
-
mConnectedThread.start();
-
}
-
/**
-
* 关闭当前客户端
-
*/
-
public void cancle() {
-
try {
-
mmSoket.close();
-
} catch (IOException e) {
-
e.printStackTrace();
-
}
-
}
-
/**
-
* 发送数据
-
* @param data
-
*/
-
public void sendData(byte[] data) {
-
if(mConnectedThread != null) {
-
mConnectedThread.write(data);
-
}
-
}
-
}
蓝牙客户端套接字BluetoothSocket
- BluetoothSocket是客户端的Socket,用于与对方设备进行数据通信。
- connect:建立蓝牙的socket连接;
- close:关闭蓝牙的socket连接;
- getInputStream:获取socket连接的输入流对象;
- getOutputStream:获取socket连接的输出流对象;
- getRemoteDevice:获取远程设备信息。
- 服务器和客户端连接上后都需要新建一个线程进行通信 不然会线程阻塞
- 发送数据需要调用BluetoothSocket的getOutputStream(),接收数据需要调用getInputStream()方法
String uuid = java.util.UUID.randomUUID().toString();
- 一般在创建Socket时需要UUID作为端口的唯一性,如果两台Android设备互联,则没有什么特殊的,
- 如果让非Android的蓝牙设备连接Android蓝牙设备,则UUID必须使用某个固定保留的UUID
- Android中创建UUID:
UUID uuid = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB")
-
package com.example.lin.mylanya.utils;
-
import android.bluetooth.BluetoothSocket;
-
import android.os.Handler;
-
import android.os.Message;
-
import android.util.Log;
-
import com.example.lin.mylanya.Constant;
-
import java.io.IOException;
-
import java.io.InputStream;
-
import java.io.OutputStream;
-
public class ConnectedThread extends Thread{
-
/** 当前连接的客户端BluetoothSocket*/
-
private final BluetoothSocket mmSokcet;
-
/** 读取数据流*/
-
private final InputStream mmInputStream;
-
/** 发送数据流*/
-
private final OutputStream mmOutputStream;
-
/** 与主线程通信Handler*/
-
private Handler mHandler;
-
private String TAG = "ConnectedThread";
-
public ConnectedThread(BluetoothSocket socket,Handler handler) {
-
mmSokcet = socket;
-
mHandler = handler;
-
InputStream tmpIn = null;
-
OutputStream tmpOut = null;
-
try {
-
tmpIn = socket.getInputStream();
-
tmpOut = socket.getOutputStream();
-
} catch (IOException e) {
-
e.printStackTrace();
-
}
-
mmInputStream = tmpIn;
-
mmOutputStream = tmpOut;
-
}
-
@Override
-
public void run() {
-
super.run();
-
byte[] buffer = new byte[1024];
-
while (true) {
-
try {
-
// 读取数据
-
int bytes = mmInputStream.read(buffer);
-
if(bytes > 0) {
-
String data = new String(buffer,0,bytes,"utf-8");
-
// 把数据发送到主线程, 此处还可以用广播
-
Message message = mHandler.obtainMessage(Constant.MSG_GOT_DATA,data);
-
mHandler.sendMessage(message);
-
}
-
Log.d(TAG, "messge size :" + bytes);
-
} catch (IOException e) {
-
e.printStackTrace();
-
}
-
}
-
}
-
// 踢掉当前客户端
-
public void cancle() {
-
try {
-
mmSokcet.close();
-
} catch (IOException e) {
-
e.printStackTrace();
-
}
-
}
-
/**
-
* 服务端发送数据
-
* @param data
-
*/
-
public void write(byte[] data) {
-
try {
-
mmOutputStream.write(data);
-
} catch (IOException e) {
-
e.printStackTrace();
-
}
-
}
-
}
ChatController
-
package com.example.lin.mylanya.utils;
-
import android.bluetooth.BluetoothAdapter;
-
import android.bluetooth.BluetoothDevice;
-
import android.os.Handler;
-
import java.io.IOException;
-
import java.io.UnsupportedEncodingException;
-
import java.net.ProtocolFamily;
-
public class ChatController {
-
/**
-
* 客户端的线程
-
*/
-
private ConnectThread mConnectThread;
-
/**
-
* 服务端的线程
-
*/
-
private AccepThread mAccepThread;
-
private ChatProtocol mProtocol = new ChatProtocol();
-
/**
-
* 网络协议的处理函数
-
*/
-
private class ChatProtocol {
-
private static final String CHARSET_NAME = "utf-8";
-
/**
-
* 封包(发送数据)
-
* 把发送的数据变成 数组 2进制流
-
*/
-
public byte[] encodePackge(String data) {
-
if (data == null) {
-
return new byte[0];
-
} else {
-
try {
-
return data.getBytes(CHARSET_NAME);
-
} catch (UnsupportedEncodingException e) {
-
e.printStackTrace();
-
return new byte[0];
-
}
-
}
-
}
-
/**
-
* 解包(接收处理数据)
-
* 把网络上数据变成自己想要的数据体
-
*/
-
public String decodePackage(byte[] netData) {
-
if (netData == null) {
-
return "";
-
} else {
-
try {
-
return new String(netData, CHARSET_NAME);
-
} catch (UnsupportedEncodingException e) {
-
e.printStackTrace();
-
return "";
-
}
-
}
-
}
-
}
-
/**
-
* 与服务器连接进行聊天
-
*/
-
public void startChatWith(BluetoothDevice device, BluetoothAdapter adapter, Handler handler) {
-
mConnectThread = new ConnectThread(device, adapter, handler);
-
mConnectThread.start();
-
}
-
/**
-
* 等待客户端来连接
-
* handler : 用来跟主线程通信,更新UI用的
-
*/
-
public void waitingForFriends(BluetoothAdapter adapter, Handler handler) {
-
try {
-
mAccepThread = new AccepThread(adapter, handler);
-
mAccepThread.start();
-
} catch (IOException e) {
-
e.printStackTrace();
-
}
-
}
-
/**
-
* 发出消息
-
*/
-
public void sendMessage(String msg) {
-
// 封包
-
byte[] data = mProtocol.encodePackge(msg);
-
if (mConnectThread != null) {
-
mConnectThread.sendData(data);
-
} else if (mAccepThread != null) {
-
mAccepThread.sendData(data);
-
}
-
}
-
/**
-
* 网络数据解码
-
*/
-
public String decodeMessage(byte[] data){
-
return mProtocol.decodePackage(data);
-
}
-
/**
-
* 停止聊天
-
*/
-
public void stopChart(){
-
if(mConnectThread != null) {
-
mConnectThread.cancle();
-
}
-
if(mAccepThread != null) {
-
mAccepThread.cancle();
-
}
-
}
-
/**
-
* 以下是单例写法
-
*/
-
private static class ChatControlHolder{
-
private static ChatController mInstance = new ChatController();
-
}
-
public static ChatController getInstance(){
-
return ChatControlHolder.mInstance;
-
}
-
}
发送数据
-
//客户端向服务器发送数据
-
String s = mEdit.getText().toString();
-
ChatController.getInstance().sendMessage(s);//发出消息
handler接收数据
-
private Handler handler = new Handler() {
-
@Override
-
public void handleMessage(Message msg) {
-
super.handleMessage(msg);
-
switch (msg.what) {
-
case MSG_GOT_DATA:
-
//接收消息
-
String data = (String) msg.obj;
-
Toast.makeText(MainActivity.this, data, Toast.LENGTH_SHORT).show();
-
break;
-
}
-
}
-
};
最后销毁:
-
@Override
-
protected void onDestroy() {
-
super.onDestroy();
-
unregisterReceiver(receiver);//关闭服务
-
mBluetoothAdapter.disable();//关闭蓝牙
-
ChatController.getInstance().stopChart();//停止聊天
-
}