蓝牙(简单的通信连接)

蓝牙是什么(Bluetooth):

  1. 一种短距离无线通信技术 
  2. 爱立信公司创建
  3. 如今由蓝牙技术联盟(Bluetooth Special Interest Group,简称SIG)管理。
  4. 现在用的都是低功耗蓝牙 Android 4.3(API Level 18)开始引入Bluetooth Low Energy(BLE,低功耗蓝牙)
  5. 在 5.0 以后才支持外设模式,

无线通信方案:

  • NFC   一个近距离接触连接的通信技术  如把手机当公交卡用  消耗最低
  • 蓝牙  一种短距离无线通信技术
  • WIFI  。。。

为什么要用蓝牙:

  • 低功率 便于电池供电设备工作
  • 使用方便,点对点连接  
  • 短距离,低成本,以及高速
  • 在智能设备的普及性高,应用广。

理论没有详细了解 这里贴出网址有兴趣可以去看下 

Android BLE的总结-概念篇

Android蓝牙BLE的详细讲解   

 

UUID:全局唯一标识 

  • UUID是根据一定算法,计算得到的一长串数字,这个数字的产生使用了多种元素,所以使得这串数字不会重复,每次生成都会产生不一样的序列,所以可以用来作为唯一标识。
  • 创建服务器端和客户端时都需要用UUID来创建 连接通讯时只有一样的才可以成功连接上
  • 可以代码生成 也可以用uuid生成器 
 UUID.randomUUID().toString().replace("-", "");

uuid


蓝牙通信的流程:

  1. 注册适配器打开蓝牙
  2. 注册广播监听蓝牙状态
  3. 搜索附近设备和已配对设备
  4. 选择未配对设备进行配对
  5. 选择已配对设备进行连接通信

1、打开蓝牙:

首先呢 先加权限 获取位置的权限属于高危权限 所以还需要动态调用:

1、AndroidManifest.xml    <6.0定位权限那别人都说只加一个就好了 我的貌似不行 所以我就都加上了>

 
  1. <!-- 蓝牙通讯权限 -->

  2. <uses-permission android:name="android.permission.BLUETOOTH" />//一些配置连接蓝牙的权限

  3. <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />//进行操作的权限

  4. <!-- 6.0以上需要的权限 -->

  5. <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

  6. <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

2、activity  

检测位置权限有没有同意 没有的话无法进行附近搜索 所以直接退出应用

 
  1. @RequiresApi(api = Build.VERSION_CODES.M)

  2. @Override

  3. protected void onResume() {

  4. super.onResume();

  5. //动态获取权限

  6. checkBluetoothAndLocationPermission();

  7. }

  8.  
  9. @RequiresApi(api = Build.VERSION_CODES.M)

  10. private void checkBluetoothAndLocationPermission() {

  11. //判断是否有访问位置的权限,没有权限,直接申请位置权限

  12. if ((checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED)

  13. || (checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED)) {

  14. requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION,

  15. Manifest.permission.ACCESS_FINE_LOCATION}, 2);

  16. }

  17. }

  18.  
  19. @Override

  20. public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {

  21. super.onRequestPermissionsResult(requestCode, permissions, grantResults);

  22.  
  23. switch (requestCode) {

  24. case 2:

  25. //再次判断是否获取到权限 没有就关闭当前界面

  26. for (int i : grantResults) {

  27. if (i != PackageManager.PERMISSION_GRANTED) {

  28. Toast.makeText(this, "Permission error !!!", Toast.LENGTH_SHORT).show();

  29. finish();

  30. }

  31. }

  32. break;

  33. }

  34. }


在onCreate()方法里,获取蓝牙适配器

BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();

BluetoothAdapter这个类常用的方法有:

  • getDefaultAdapter: 获取本地的蓝牙适配器
  • enable(); 打开蓝牙(不带提示框 但是手机有自带的。。。)
  • disable(); 关闭蓝牙
  • isEnabled(): 本地蓝牙是否打开
  • getAddress(); 获取自己的蓝牙MAC地址
  • cancelDiscovery() 停止扫描
  • isDiscovering() 是否正在处于扫描过程中
  • getState():获取本地蓝牙适配器的状态
  • getScanMode(): 获取本地蓝牙适配器的当前蓝牙扫描模式。

详细用法表

打开蓝牙的两种方式:

  • 第一种打开方法: 调用enable 
  • 第二种打开方法 ,调用系统API去打开蓝牙
 
  1. mBluetoothAdapter.enable();

  2. //不会自动提示用户默认打开 有的手机还是会提示的

  3.  
  4.  
  5. Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);

  6. startActivityForResult(intent, REQUEST_OPEN_BT_CODE); //CODE值只是标记可以更改

  7. //会以Dialog样式显示一个Activity , 我们可以在onActivityResult()方法去处理返回值

 


接下来为了保险起见先判断设备是否支持蓝牙:

 
  1. if(mBluetoothAdapter == null){

  2. Toast.makeText(this,"本地蓝牙不可用",Toast.LENGTH_SHORT).show();

  3. finish(); //退出应用

  4. }

确认支持蓝牙的话就可以调用蓝牙适配器的方法了:

 
  1. String Address = bluetoothAdapter.getAddress(); //获取本机蓝牙MAC地址

  2. String Name = bluetoothAdapter.getName(); //获取本机蓝牙名称

  3. // 若蓝牙没打开

  4. if(!bluetoothAdapter.isEnabled()){

  5. bluetoothAdapter.enable(); //打开蓝牙

  6. }

上边这些除了 打开蓝牙其他的并没有什么用处 这里只是举个例子


设置可以被搜索到  

 
  1. //设置可以被搜索到

  2. //判断蓝牙适配器的当前蓝牙扫描模式

  3. if (mBluetoothAdapter.getScanMode() != BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE)

  4. {

  5. Intent discoverableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);

  6. // 设置被发现时间,最大值是3600秒,0表示设备总是可以被发现的(小于0或者大于3600则会被自动设置为120秒)

  7. discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 120);

  8. startActivity(discoverableIntent);

  9. }


接下来开始搜索附近:

判断是否正在搜索 如果是就停止搜索之类的 

 
  1. if (!mBluetoothAdapter.isDiscovering()) {//判断是否正在搜索

  2. mBluetoothAdapter.startDiscovery();//开始搜索附近设备

  3. textView2.setText("正在搜索...");

  4.  
  5. } else {

  6. mBluetoothAdapter.cancelDiscovery();//停止搜索

  7. }

搜索附近需要先注册个广播来监听查询附近蓝牙设备:

蓝牙扫描时,扫描到任一远程蓝牙设备时,会发送此广播。两种广播用一个就行

注册分为两种:静态注册和动态注册。

  • 静态注册就是在AndroidManifest.xml文件中定义,
  • 注册的广播接收器必须继承BroadReceiver 动态注册就是在程序中使用Context.registerReceiver注册。

动态广播

 
  1. //注册广播

  2. IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);//搜索到设备

  3. registerReceiver(receiver, filter);

  4. IntentFilter filter2 = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);//搜索结束

  5. registerReceiver(receiver, filter2);

静态广播

 
  1. <!-- 广播接收 -->

  2. <receiver android:name="包名.类名" >

  3. <intent-filter android:priority="1000">

  4. <action android:name="android.bluetooth.adapter.action.DISCOVERY_FINISHED"/>

  5. <action android:name="android.bluetooth.device.action.FOUND" />

  6. </intent-filter>

  7. </receiver>

new个BroadcastReceiver来接收:

广播一旦发送 这边就会调用 onReceive()方法

 
  1. BroadcastReceiver receiver = new BroadcastReceiver() {

  2. @Override

  3. public void onReceive(Context context, Intent intent) {

  4. String action = intent.getAction();

  5.  
  6. if (action.equals(BluetoothDevice.ACTION_FOUND)) {

  7. //获取已配对蓝牙设备

  8. Set<BluetoothDevice> devices = mBluetoothAdapter.getBondedDevices();

  9.  
  10. for (BluetoothDevice bonddevice : devices) {

  11. mPeiDuiList.add(bonddevice);

  12. peiDuiAdapter.notifyDataSetChanged();

  13. }

  14.  
  15. BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);

  16. //判断未配对的设备

  17. if (device.getBondState() != BluetoothDevice.BOND_BONDED) {

  18. mFuJinList.add(device);

  19. fuJinAdapter.notifyDataSetChanged();

  20. }

  21. } else if (action.equals(BluetoothAdapter.ACTION_DISCOVERY_FINISHED)) {

  22. textView2.setText("搜索完成...");

  23. }

  24. }

  25. };

我这边是创建了两个集合 分别把已配对的和附近的储存进去

 
  1. private ArrayList<BluetoothDevice> mPeiDuiList = new ArrayList<>();

  2. private ArrayList<BluetoothDevice> mFuJinList = new ArrayList<>();

 接下来把获取到的数据放入适配器显示 这步我就不写了 大家都会

这里用到了蓝牙设备BluetoothDevice

BluetoothDevice用于指代某个蓝牙设备,通常表示对方设备

  • getName:获得该设备的名称; 
  • getAddress:获得该设备的地址; 
  • createRfcommSocketToServiceRecord:根据UUID创建并返回一个BluetoothSocket。

1 配对

两个设备建立连接以后,就可以进行一个配对的过程。

配对进行的时候,会产生一个密钥用来加密与鉴别连接。一个典型的情况是,从机设备会要求主机设备提供一个密码来完成一个配对过程。

这个密码可以是固定的例如“000000”,也可以是提供给上层的随机产生的一个值。当主机设备发送一个正确的密码是,这两个设备就会相互交换密钥来加密并鉴别连接。

2 绑定

很多情况下,两个设备会需要经常性的断开连接,连接这样的过程,BLE有一个安全功能,允许两台设备配对的时候给对方一个长期的一套安全密钥。
这种机制称作为绑定。允许两个设备再次连接时不需要再次进行配对就能从新加密与鉴别,只要他们存储了这个安全密钥。

配对:

主要写配对和通信 绑定先不多做介绍

 
  1. //点击附近的开始配对

  2. mBluetoothAdapter.cancelDiscovery();//停止搜索

  3. String address = mFuJinList.get(position).getAddress();

  4. Toast.makeText(MainActivity.this, mFuJinList.get(position).getName() + "配对中。。。", Toast.LENGTH_SHORT).show();

  5.  
  6. try {

  7. //调用工具类与设备配对

  8. //已知自己的地址 点击获取对方的地址 配对

  9. remoteDevice = mBluetoothAdapter.getRemoteDevice(address);//通过mac地址获取蓝牙设备

  10. ClsUtils.createBond(remoteDevice.getClass(), remoteDevice);

  11. } catch (Exception e) {

  12. e.printStackTrace();

  13.  
  14. }

这里用到了一个配对工具类ClsUtils

 
  1. package com.example.lin.mylanya.utils;

  2.  
  3.  
  4. import java.lang.reflect.Field;

  5. import java.lang.reflect.Method;

  6.  
  7. import android.bluetooth.BluetoothDevice;

  8. import android.util.Log;

  9.  
  10. public class ClsUtils {

  11.  
  12. /**

  13. * 与设备配对 参考源码:platform/packages/apps/Settings.git

  14. * /Settings/src/com/android/settings/bluetooth/CachedBluetoothDevice.java

  15. */

  16. static public boolean createBond(Class btClass,BluetoothDevice btDevice) throws Exception {

  17. Method createBondMethod = btClass.getMethod("createBond");

  18. Boolean returnValue = (Boolean) createBondMethod.invoke(btDevice);

  19. return returnValue.booleanValue();

  20. }

  21.  
  22. /**

  23. * 与设备解除配对 参考源码:platform/packages/apps/Settings.git

  24. * /Settings/src/com/android/settings/bluetooth/CachedBluetoothDevice.java

  25. */

  26. static public boolean removeBond(Class btClass,BluetoothDevice btDevice) throws Exception {

  27. Method removeBondMethod = btClass.getMethod("removeBond");

  28. Boolean returnValue = (Boolean) removeBondMethod.invoke(btDevice);

  29. return returnValue.booleanValue();

  30. }

  31.  
  32. }

 


通信:

通信需要创建客户端和服务器来建立连接

通讯是耗时操作所以都用另建了一个类继承Thread来写了

先创建服务器:

服务器一般是在打开蓝牙后创建  这里的ChatController是通信的工具类 这个方法里面调用了服务器线程(AccepThread)的启动方法

 
  1.  
  2. if (!mBluetoothAdapter.isEnabled()) {//判断蓝牙是否打开

  3. mBluetoothAdapter.enable();//打开蓝牙

  4. }

  5. ChatController.getInstance().waitingForFriends(mBluetoothAdapter, handler);//等待客户端来连接

  •  服务器端建立套接字,等待客户端连接,
  • 调用BluetoothAdapter的listenUsingRfcommWithServiceRecord方法,产生一个BluetoothServerSocket对象,
  • 然后调用BluetoothServerSocket对象的accept方法,
  • 注意accept方法会产生阻塞,直到一个客户端连接建立,所以服务器端的socket的建立需要在一个子线程中去做,

AccepThread

 
  1. package com.example.lin.mylanya.utils;

  2.  
  3. import android.bluetooth.BluetoothAdapter;

  4. import android.bluetooth.BluetoothServerSocket;

  5. import android.bluetooth.BluetoothSocket;

  6. import android.os.Handler;

  7.  
  8. import com.example.lin.mylanya.Constant;

  9.  
  10. import java.io.IOException;

  11. import java.util.UUID;

  12.  
  13. public class AccepThread extends Thread {

  14.  
  15. /** 连接的名称*/

  16. private static final String NAME = "BluetoothClass";

  17. /** UUID*/

  18. private static final UUID MY_UUID = UUID.fromString(Constant.CONNECTTION_UUID);

  19. /** 服务端蓝牙Sokcet*/

  20. private final BluetoothServerSocket mmServerSocket;

  21. private final BluetoothAdapter mBluetoothAdapter;

  22. /** 线程中通信的更新UI的Handler*/

  23. private final Handler mHandler;

  24. /** 监听到有客户端连接,新建一个线程单独处理,不然在此线程中会堵塞*/

  25. private ConnectedThread mConnectedThread;

  26.  
  27. public AccepThread(BluetoothAdapter adapter, Handler handler) throws IOException {

  28. mBluetoothAdapter = adapter;

  29. this.mHandler = handler;

  30.  
  31. // 获取服务端蓝牙socket

  32. mmServerSocket = mBluetoothAdapter.listenUsingRfcommWithServiceRecord(NAME, MY_UUID);

  33. }

  34.  
  35. @Override

  36. public void run() {

  37. super.run();

  38. // 连接的客户端soacket

  39. BluetoothSocket socket = null;

  40. // 服务端是不退出的,要一直监听连接进来的客户端,所以是死循环

  41. while (true){

  42.  
  43. try {

  44. // 获取连接的客户端socket

  45. socket = mmServerSocket.accept();

  46. } catch (IOException e) {

  47. // 通知主线程更新UI, 获取异常

  48. mHandler.sendEmptyMessage(Constant.MSG_ERROR);

  49. e.printStackTrace();

  50. // 服务端退出一直监听线程

  51. break;

  52. }

  53.  
  54. if(socket != null) {

  55. // 管理连接的客户端socket

  56. manageConnectSocket(socket);

  57. }

  58. }

  59. }

  60.  
  61. /**

  62. * 管理连接的客户端socket

  63. * @param socket

  64. */

  65. private void manageConnectSocket(BluetoothSocket socket) {

  66. // 只支持同时处理一个连接

  67. // mConnectedThread不为空,踢掉之前的客户端

  68. if(mConnectedThread != null) {

  69. mConnectedThread.cancle();

  70. }

  71.  
  72. // 新建一个线程,处理客户端发来的数据

  73. mConnectedThread = new ConnectedThread(socket, mHandler);

  74. mConnectedThread.start();

  75. }

  76.  
  77. /**

  78. * 断开服务端,结束监听

  79. */

  80. public void cancle() {

  81. try {

  82. mmServerSocket.close();

  83. mHandler.sendEmptyMessage(Constant.MSG_FINISH_LISTENING);

  84. } catch (IOException e) {

  85. e.printStackTrace();

  86. }

  87. }

  88.  
  89. /**

  90. * 发送数据

  91. * @param data

  92. */

  93. public void sendData(byte[] data){

  94. if(mConnectedThread != null) {

  95. mConnectedThread.write(data);

  96. }

  97. }

  98. }

蓝牙服务器套接字BluetoothServiceSocket

  • BluetoothServiceSocket是服务端的Socket,用来接收客户端的Socket连接请求
  • accept:监听外部的蓝牙连接请求; 
  • close:关闭服务端的蓝牙监听。
  • 当远端设备连接到了的时候,Blueboothserversocket 类将会返回一个 bluetoothsocket。


客户端:

客户端是在点击连接时调用  同上 是不过是调用了客户端线程的启动方法

 
  1. //点击连接

  2. String address = mPeiDuiList.get(position).getAddress();

  3. String name = mPeiDuiList.get(position).getName();

  4. Toast.makeText(MainActivity.this, name + "开始连接 请稍后。。。", Toast.LENGTH_SHORT).show();

  5. remoteDevice = mBluetoothAdapter.getRemoteDevice(address);

  6.  
  7. ChatController.getInstance().startChatWith(remoteDevice, mBluetoothAdapter, handler);//与服务器连接进行聊天 也就是客户端连接服务端

  •  客户端去连接服务器端,需要先持有服务器端的BluetoothDevice对象,
  • 先调用BluetoothDevice的createRfcommSocketToServiceRecord方法,这个方法会产生一个客户端的BluetoothSocket对象,
  • 然后调用该对象的connect方法,该过程最好也是单独起一个线程去做
  • 创建客户端需要一个UUID
 
  1. package com.example.lin.mylanya.utils;

  2.  
  3. import android.bluetooth.BluetoothAdapter;

  4. import android.bluetooth.BluetoothDevice;

  5. import android.bluetooth.BluetoothSocket;

  6. import android.os.Handler;

  7.  
  8. import com.example.lin.mylanya.Constant;

  9. import com.example.lin.mylanya.utils.ConnectedThread;

  10.  
  11. import java.io.IOException;

  12. import java.util.UUID;

  13.  
  14. public class ConnectThread extends Thread{

  15. private static final UUID MY_UUID = UUID.fromString(Constant.CONNECTTION_UUID);

  16. /** 客户端socket*/

  17. private final BluetoothSocket mmSoket;

  18. /** 要连接的设备*/

  19. private final BluetoothDevice mmDevice;

  20. private BluetoothAdapter mBluetoothAdapter;

  21. /** 主线程通信的Handler*/

  22. private final Handler mHandler;

  23. /** 发送和接收数据的处理类*/

  24. private ConnectedThread mConnectedThread;

  25.  
  26. public ConnectThread(BluetoothDevice device, BluetoothAdapter bluetoothAdapter, Handler mUIhandler) {

  27. mmDevice = device;

  28. mBluetoothAdapter = bluetoothAdapter;

  29. mHandler = mUIhandler;

  30.  
  31. BluetoothSocket tmp = null;

  32. try {

  33. // 创建客户端Socket

  34. tmp = device.createRfcommSocketToServiceRecord(MY_UUID);

  35. } catch (IOException e) {

  36. e.printStackTrace();

  37. }

  38. mmSoket = tmp;

  39. }

  40.  
  41. @Override

  42. public void run() {

  43. super.run();

  44. // 关闭正在发现设备.(如果此时又在查找设备,又在发送数据,会有冲突,影响传输效率)

  45. mBluetoothAdapter.cancelDiscovery();

  46. try {

  47. // 连接服务器

  48. mmSoket.connect();

  49. } catch (IOException e) {

  50. // 连接异常就关闭

  51. try {

  52. mmSoket.close();

  53. } catch (IOException e1) {

  54. }

  55. return;

  56. }

  57.  
  58. manageConnectedSocket(mmSoket);

  59. }

  60.  
  61. private void manageConnectedSocket(BluetoothSocket mmSoket) {

  62.  
  63. // 新建一个线程进行通讯,不然会发现线程堵塞

  64. mConnectedThread = new ConnectedThread(mmSoket,mHandler);

  65. mConnectedThread.start();

  66. }

  67.  
  68. /**

  69. * 关闭当前客户端

  70. */

  71. public void cancle() {

  72. try {

  73. mmSoket.close();

  74. } catch (IOException e) {

  75. e.printStackTrace();

  76. }

  77. }

  78.  
  79. /**

  80. * 发送数据

  81. * @param data

  82. */

  83. public void sendData(byte[] data) {

  84. if(mConnectedThread != null) {

  85. mConnectedThread.write(data);

  86. }

  87. }

  88. }

蓝牙客户端套接字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")
 
  1. package com.example.lin.mylanya.utils;

  2.  
  3. import android.bluetooth.BluetoothSocket;

  4. import android.os.Handler;

  5. import android.os.Message;

  6. import android.util.Log;

  7.  
  8. import com.example.lin.mylanya.Constant;

  9.  
  10. import java.io.IOException;

  11. import java.io.InputStream;

  12. import java.io.OutputStream;

  13.  
  14. public class ConnectedThread extends Thread{

  15. /** 当前连接的客户端BluetoothSocket*/

  16. private final BluetoothSocket mmSokcet;

  17. /** 读取数据流*/

  18. private final InputStream mmInputStream;

  19. /** 发送数据流*/

  20. private final OutputStream mmOutputStream;

  21. /** 与主线程通信Handler*/

  22. private Handler mHandler;

  23. private String TAG = "ConnectedThread";

  24.  
  25. public ConnectedThread(BluetoothSocket socket,Handler handler) {

  26. mmSokcet = socket;

  27. mHandler = handler;

  28.  
  29. InputStream tmpIn = null;

  30. OutputStream tmpOut = null;

  31. try {

  32. tmpIn = socket.getInputStream();

  33. tmpOut = socket.getOutputStream();

  34. } catch (IOException e) {

  35. e.printStackTrace();

  36. }

  37.  
  38. mmInputStream = tmpIn;

  39. mmOutputStream = tmpOut;

  40. }

  41.  
  42. @Override

  43. public void run() {

  44. super.run();

  45. byte[] buffer = new byte[1024];

  46.  
  47. while (true) {

  48. try {

  49. // 读取数据

  50. int bytes = mmInputStream.read(buffer);

  51.  
  52. if(bytes > 0) {

  53. String data = new String(buffer,0,bytes,"utf-8");

  54. // 把数据发送到主线程, 此处还可以用广播

  55. Message message = mHandler.obtainMessage(Constant.MSG_GOT_DATA,data);

  56. mHandler.sendMessage(message);

  57. }

  58. Log.d(TAG, "messge size :" + bytes);

  59. } catch (IOException e) {

  60. e.printStackTrace();

  61. }

  62. }

  63. }

  64.  
  65. // 踢掉当前客户端

  66. public void cancle() {

  67. try {

  68. mmSokcet.close();

  69. } catch (IOException e) {

  70. e.printStackTrace();

  71. }

  72. }

  73.  
  74. /**

  75. * 服务端发送数据

  76. * @param data

  77. */

  78. public void write(byte[] data) {

  79. try {

  80. mmOutputStream.write(data);

  81. } catch (IOException e) {

  82. e.printStackTrace();

  83. }

  84. }

  85. }

ChatController

 
  1. package com.example.lin.mylanya.utils;

  2.  
  3. import android.bluetooth.BluetoothAdapter;

  4. import android.bluetooth.BluetoothDevice;

  5. import android.os.Handler;

  6.  
  7. import java.io.IOException;

  8. import java.io.UnsupportedEncodingException;

  9. import java.net.ProtocolFamily;

  10.  
  11. public class ChatController {

  12. /**

  13. * 客户端的线程

  14. */

  15. private ConnectThread mConnectThread;

  16. /**

  17. * 服务端的线程

  18. */

  19. private AccepThread mAccepThread;

  20. private ChatProtocol mProtocol = new ChatProtocol();

  21.  
  22. /**

  23. * 网络协议的处理函数

  24. */

  25. private class ChatProtocol {

  26. private static final String CHARSET_NAME = "utf-8";

  27.  
  28. /**

  29. * 封包(发送数据)

  30. * 把发送的数据变成 数组 2进制流

  31. */

  32. public byte[] encodePackge(String data) {

  33. if (data == null) {

  34. return new byte[0];

  35. } else {

  36. try {

  37. return data.getBytes(CHARSET_NAME);

  38. } catch (UnsupportedEncodingException e) {

  39. e.printStackTrace();

  40. return new byte[0];

  41. }

  42. }

  43. }

  44.  
  45. /**

  46. * 解包(接收处理数据)

  47. * 把网络上数据变成自己想要的数据体

  48. */

  49. public String decodePackage(byte[] netData) {

  50. if (netData == null) {

  51. return "";

  52. } else {

  53. try {

  54. return new String(netData, CHARSET_NAME);

  55. } catch (UnsupportedEncodingException e) {

  56. e.printStackTrace();

  57. return "";

  58. }

  59. }

  60. }

  61.  
  62.  
  63. }

  64.  
  65. /**

  66. * 与服务器连接进行聊天

  67. */

  68. public void startChatWith(BluetoothDevice device, BluetoothAdapter adapter, Handler handler) {

  69. mConnectThread = new ConnectThread(device, adapter, handler);

  70. mConnectThread.start();

  71. }

  72.  
  73. /**

  74. * 等待客户端来连接

  75. * handler : 用来跟主线程通信,更新UI用的

  76. */

  77. public void waitingForFriends(BluetoothAdapter adapter, Handler handler) {

  78. try {

  79. mAccepThread = new AccepThread(adapter, handler);

  80. mAccepThread.start();

  81. } catch (IOException e) {

  82. e.printStackTrace();

  83. }

  84. }

  85.  
  86. /**

  87. * 发出消息

  88. */

  89. public void sendMessage(String msg) {

  90. // 封包

  91. byte[] data = mProtocol.encodePackge(msg);

  92.  
  93. if (mConnectThread != null) {

  94. mConnectThread.sendData(data);

  95. } else if (mAccepThread != null) {

  96. mAccepThread.sendData(data);

  97. }

  98. }

  99.  
  100. /**

  101. * 网络数据解码

  102. */

  103. public String decodeMessage(byte[] data){

  104. return mProtocol.decodePackage(data);

  105. }

  106.  
  107. /**

  108. * 停止聊天

  109. */

  110. public void stopChart(){

  111. if(mConnectThread != null) {

  112. mConnectThread.cancle();

  113. }

  114. if(mAccepThread != null) {

  115. mAccepThread.cancle();

  116. }

  117. }

  118.  
  119.  
  120. /**

  121. * 以下是单例写法

  122. */

  123. private static class ChatControlHolder{

  124. private static ChatController mInstance = new ChatController();

  125. }

  126.  
  127. public static ChatController getInstance(){

  128. return ChatControlHolder.mInstance;

  129. }

  130.  
  131. }


发送数据

 
  1. //客户端向服务器发送数据

  2. String s = mEdit.getText().toString();

  3. ChatController.getInstance().sendMessage(s);//发出消息

handler接收数据

 
  1. private Handler handler = new Handler() {

  2. @Override

  3. public void handleMessage(Message msg) {

  4. super.handleMessage(msg);

  5. switch (msg.what) {

  6.  
  7. case MSG_GOT_DATA:

  8. //接收消息

  9. String data = (String) msg.obj;

  10. Toast.makeText(MainActivity.this, data, Toast.LENGTH_SHORT).show();

  11. break;

  12. }

  13. }

  14. };

最后销毁:

 
  1. @Override

  2. protected void onDestroy() {

  3. super.onDestroy();

  4. unregisterReceiver(receiver);//关闭服务

  5. mBluetoothAdapter.disable();//关闭蓝牙

  6. ChatController.getInstance().stopChart();//停止聊天

  7. }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值