蓝牙是什么(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. @RequiresApi(api = Build.VERSION_CODES.M)

  9. private void checkBluetoothAndLocationPermission() {

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

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

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

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

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

  15. }

  16. }

  17. @Override

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

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

  20. switch (requestCode) {

  21. case 2:

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

  23. for (int i : grantResults) {

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

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

  26. finish();

  27. }

  28. }

  29. break;

  30. }

  31. }


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

BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();

BluetoothAdapter这个类常用的方法有:

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

详细用法表

打开蓝牙的两种方式:

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

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

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

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

  5. //会以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. } else {

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

  6. }

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

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

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

  • 静态注册就是在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. if (action.equals(BluetoothDevice.ACTION_FOUND)) {

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

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

  8. for (BluetoothDevice bonddevice : devices) {

  9. mPeiDuiList.add(bonddevice);

  10. peiDuiAdapter.notifyDataSetChanged();

  11. }

  12. BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);

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

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

  15. mFuJinList.add(device);

  16. fuJinAdapter.notifyDataSetChanged();

  17. }

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

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

  20. }

  21. }

  22. };

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

  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. try {

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

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

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

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

  10. } catch (Exception e) {

  11. e.printStackTrace();

  12. }

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

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

  2. import java.lang.reflect.Field;

  3. import java.lang.reflect.Method;

  4. import android.bluetooth.BluetoothDevice;

  5. import android.util.Log;

  6. public class ClsUtils {

  7. /**

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

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

  10. */

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

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

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

  14. return returnValue.booleanValue();

  15. }

  16. /**

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

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

  19. */

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

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

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

  23. return returnValue.booleanValue();

  24. }

  25. }


通信:

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

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

先创建服务器:

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

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

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

  3. }

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

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

AccepThread

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

  2. import android.bluetooth.BluetoothAdapter;

  3. import android.bluetooth.BluetoothServerSocket;

  4. import android.bluetooth.BluetoothSocket;

  5. import android.os.Handler;

  6. import com.example.lin.mylanya.Constant;

  7. import java.io.IOException;

  8. import java.util.UUID;

  9. public class AccepThread extends Thread {

  10. /** 连接的名称*/

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

  12. /** UUID*/

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

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

  15. private final BluetoothServerSocket mmServerSocket;

  16. private final BluetoothAdapter mBluetoothAdapter;

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

  18. private final Handler mHandler;

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

  20. private ConnectedThread mConnectedThread;

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

  22. mBluetoothAdapter = adapter;

  23. this.mHandler = handler;

  24. // 获取服务端蓝牙socket

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

  26. }

  27. @Override

  28. public void run() {

  29. super.run();

  30. // 连接的客户端soacket

  31. BluetoothSocket socket = null;

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

  33. while (true){

  34. try {

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

  36. socket = mmServerSocket.accept();

  37. } catch (IOException e) {

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

  39. mHandler.sendEmptyMessage(Constant.MSG_ERROR);

  40. e.printStackTrace();

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

  42. break;

  43. }

  44. if(socket != null) {

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

  46. manageConnectSocket(socket);

  47. }

  48. }

  49. }

  50. /**

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

  52. * @param socket

  53. */

  54. private void manageConnectSocket(BluetoothSocket socket) {

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

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

  57. if(mConnectedThread != null) {

  58. mConnectedThread.cancle();

  59. }

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

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

  62. mConnectedThread.start();

  63. }

  64. /**

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

  66. */

  67. public void cancle() {

  68. try {

  69. mmServerSocket.close();

  70. mHandler.sendEmptyMessage(Constant.MSG_FINISH_LISTENING);

  71. } catch (IOException e) {

  72. e.printStackTrace();

  73. }

  74. }

  75. /**

  76. * 发送数据

  77. * @param data

  78. */

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

  80. if(mConnectedThread != null) {

  81. mConnectedThread.write(data);

  82. }

  83. }

  84. }

蓝牙服务器套接字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. ChatController.getInstance().startChatWith(remoteDevice, mBluetoothAdapter, handler);//与服务器连接进行聊天 也就是客户端连接服务端

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

  2. import android.bluetooth.BluetoothAdapter;

  3. import android.bluetooth.BluetoothDevice;

  4. import android.bluetooth.BluetoothSocket;

  5. import android.os.Handler;

  6. import com.example.lin.mylanya.Constant;

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

  8. import java.io.IOException;

  9. import java.util.UUID;

  10. public class ConnectThread extends Thread{

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

  12. /** 客户端socket*/

  13. private final BluetoothSocket mmSoket;

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

  15. private final BluetoothDevice mmDevice;

  16. private BluetoothAdapter mBluetoothAdapter;

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

  18. private final Handler mHandler;

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

  20. private ConnectedThread mConnectedThread;

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

  22. mmDevice = device;

  23. mBluetoothAdapter = bluetoothAdapter;

  24. mHandler = mUIhandler;

  25. BluetoothSocket tmp = null;

  26. try {

  27. // 创建客户端Socket

  28. tmp = device.createRfcommSocketToServiceRecord(MY_UUID);

  29. } catch (IOException e) {

  30. e.printStackTrace();

  31. }

  32. mmSoket = tmp;

  33. }

  34. @Override

  35. public void run() {

  36. super.run();

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

  38. mBluetoothAdapter.cancelDiscovery();

  39. try {

  40. // 连接服务器

  41. mmSoket.connect();

  42. } catch (IOException e) {

  43. // 连接异常就关闭

  44. try {

  45. mmSoket.close();

  46. } catch (IOException e1) {

  47. }

  48. return;

  49. }

  50. manageConnectedSocket(mmSoket);

  51. }

  52. private void manageConnectedSocket(BluetoothSocket mmSoket) {

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

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

  55. mConnectedThread.start();

  56. }

  57. /**

  58. * 关闭当前客户端

  59. */

  60. public void cancle() {

  61. try {

  62. mmSoket.close();

  63. } catch (IOException e) {

  64. e.printStackTrace();

  65. }

  66. }

  67. /**

  68. * 发送数据

  69. * @param data

  70. */

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

  72. if(mConnectedThread != null) {

  73. mConnectedThread.write(data);

  74. }

  75. }

  76. }

蓝牙客户端套接字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. import android.bluetooth.BluetoothSocket;

  3. import android.os.Handler;

  4. import android.os.Message;

  5. import android.util.Log;

  6. import com.example.lin.mylanya.Constant;

  7. import java.io.IOException;

  8. import java.io.InputStream;

  9. import java.io.OutputStream;

  10. public class ConnectedThread extends Thread{

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

  12. private final BluetoothSocket mmSokcet;

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

  14. private final InputStream mmInputStream;

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

  16. private final OutputStream mmOutputStream;

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

  18. private Handler mHandler;

  19. private String TAG = "ConnectedThread";

  20. public ConnectedThread(BluetoothSocket socket,Handler handler) {

  21. mmSokcet = socket;

  22. mHandler = handler;

  23. InputStream tmpIn = null;

  24. OutputStream tmpOut = null;

  25. try {

  26. tmpIn = socket.getInputStream();

  27. tmpOut = socket.getOutputStream();

  28. } catch (IOException e) {

  29. e.printStackTrace();

  30. }

  31. mmInputStream = tmpIn;

  32. mmOutputStream = tmpOut;

  33. }

  34. @Override

  35. public void run() {

  36. super.run();

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

  38. while (true) {

  39. try {

  40. // 读取数据

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

  42. if(bytes > 0) {

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

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

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

  46. mHandler.sendMessage(message);

  47. }

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

  49. } catch (IOException e) {

  50. e.printStackTrace();

  51. }

  52. }

  53. }

  54. // 踢掉当前客户端

  55. public void cancle() {

  56. try {

  57. mmSokcet.close();

  58. } catch (IOException e) {

  59. e.printStackTrace();

  60. }

  61. }

  62. /**

  63. * 服务端发送数据

  64. * @param data

  65. */

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

  67. try {

  68. mmOutputStream.write(data);

  69. } catch (IOException e) {

  70. e.printStackTrace();

  71. }

  72. }

  73. }

ChatController

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

  2. import android.bluetooth.BluetoothAdapter;

  3. import android.bluetooth.BluetoothDevice;

  4. import android.os.Handler;

  5. import java.io.IOException;

  6. import java.io.UnsupportedEncodingException;

  7. import java.net.ProtocolFamily;

  8. public class ChatController {

  9. /**

  10. * 客户端的线程

  11. */

  12. private ConnectThread mConnectThread;

  13. /**

  14. * 服务端的线程

  15. */

  16. private AccepThread mAccepThread;

  17. private ChatProtocol mProtocol = new ChatProtocol();

  18. /**

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

  20. */

  21. private class ChatProtocol {

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

  23. /**

  24. * 封包(发送数据)

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

  26. */

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

  28. if (data == null) {

  29. return new byte[0];

  30. } else {

  31. try {

  32. return data.getBytes(CHARSET_NAME);

  33. } catch (UnsupportedEncodingException e) {

  34. e.printStackTrace();

  35. return new byte[0];

  36. }

  37. }

  38. }

  39. /**

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

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

  42. */

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

  44. if (netData == null) {

  45. return "";

  46. } else {

  47. try {

  48. return new String(netData, CHARSET_NAME);

  49. } catch (UnsupportedEncodingException e) {

  50. e.printStackTrace();

  51. return "";

  52. }

  53. }

  54. }

  55. }

  56. /**

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

  58. */

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

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

  61. mConnectThread.start();

  62. }

  63. /**

  64. * 等待客户端来连接

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

  66. */

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

  68. try {

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

  70. mAccepThread.start();

  71. } catch (IOException e) {

  72. e.printStackTrace();

  73. }

  74. }

  75. /**

  76. * 发出消息

  77. */

  78. public void sendMessage(String msg) {

  79. // 封包

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

  81. if (mConnectThread != null) {

  82. mConnectThread.sendData(data);

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

  84. mAccepThread.sendData(data);

  85. }

  86. }

  87. /**

  88. * 网络数据解码

  89. */

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

  91. return mProtocol.decodePackage(data);

  92. }

  93. /**

  94. * 停止聊天

  95. */

  96. public void stopChart(){

  97. if(mConnectThread != null) {

  98. mConnectThread.cancle();

  99. }

  100. if(mAccepThread != null) {

  101. mAccepThread.cancle();

  102. }

  103. }

  104. /**

  105. * 以下是单例写法

  106. */

  107. private static class ChatControlHolder{

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

  109. }

  110. public static ChatController getInstance(){

  111. return ChatControlHolder.mInstance;

  112. }

  113. }


发送数据

  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. case MSG_GOT_DATA:

  7. //接收消息

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

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

  10. break;

  11. }

  12. }

  13. };

最后销毁:

  1. @Override

  2. protected void onDestroy() {

  3. super.onDestroy();

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

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

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

  7. }

蓝牙(简单的通信连接)相关推荐

  1. android 蓝牙搜索、配对连接通信总结

    蓝牙协议可以实现一个蓝牙设备和6到8个蓝牙设备进行通信. 1.蓝牙搜索的实现 利用蓝牙的发现和完成动作动态注册广播接受者获得蓝牙设备. 第一步,获得蓝牙适配器 BluetoothAdapter mBt ...

  2. 使用蓝牙测试app和Web Bluetooth API(web蓝牙)连接arduino蓝牙模块并通信

    原文链接:https://dsx2016.com/?p=1505 公众号:大师兄2016 前言 前面的arduino操作都是建立在usb串口通信上的,然而有线的操作不仅不方便,还受限设备数量,数据传输 ...

  3. Android中如何实现蓝牙的配对与连接

    Android中如何实现蓝牙的配对与连接 这段时间在项目中负责做蓝牙的设置模块,蓝牙这部分不算简单,自己先是花了一些时间看系统的蓝牙设置代码,感觉有点熟了才开动的,但期间还是踩了不少坑,有些问题网上也 ...

  4. Android-经典蓝牙(BT)-建立长连接传输短消息和文件

    参考: https://developer.android.com/guide/topics/connectivity/bluetooth http://bbs.eeworld.com.cn/thre ...

  5. Android端 同 单片机 利用蓝牙模块的通信实现

    这次期末的课程设计做了一个智能灯光控制系统,系统整体的功能不在此赘述,系统主要是要实现下位机同上位机的通信,上位机选用的是Android手机端,下位机是52单片机,通过蓝牙模块实现通信.虽然系统很简单 ...

  6. Android与蓝牙串口模块通信

    由于项目的需要的Android与蓝牙模块通信,发了时间学习了下,实现了Android的与蓝牙模块的通信 1.蓝牙串口模块使用SPP-CA模块 蓝牙串口模块就是使用单片机的TX,RX与蓝牙模块通信, ...

  7. 【IOT开发】蓝牙模块与PC连接通讯实验

    这是在一个项目中,需要开发 windows APP,通过蓝牙与下位机通讯.之前接触过的一些蓝牙项目,大多是 模块与模块 通讯,也见过很多模块-手机通讯的教程,但PC端直接与蓝牙模块的连接教程比较少,买 ...

  8. win10蓝牙允许设备连接到此计算机,蓝牙允许设备进行连接用不了_win10蓝牙允许设备连接灰色怎么解决...

    手机可以连接多个蓝牙设备吗 手机连接多个蓝牙耳机的方法 在如今的智能设备中像手机.电脑等设备中都集成了蓝牙功能,我们经常会使用到这一功能,不过近日有用户在使用时,有一疑问,那就是手机可以连接多个蓝牙设 ...

  9. 安卓蓝牙4.0通信之Socket图片传输

    安卓蓝牙4.0Socket通信传输图片 开发环境介绍: 开发工具:AndroidStudio 3.1.2 测试机:华为荣耀八青春版 安卓8.0(7.0) 红米note1S(4.4) SDK版本:28 ...

  10. Arduino使用HC05蓝牙模块与手机连接(转载)

    通过本文,可以了解到以下内容: 进入 AT 模式进行蓝牙基本参数设置 Arduino 蓝牙控制 LED 电路设计以及代码编写 利用 Andorid 蓝牙串口调试软件测试功能 进入 At 模式进行蓝牙基 ...

最新文章

  1. R Learnilng 十八讲7-12
  2. python m什么意思_Python -m参数原理及使用方法解析
  3. PowerBI 秒级实时大屏展示方案 全面助力双十一
  4. 网络工程师晋升_晋升为工程师的最快方法
  5. 云原生实时数仓首次在2020双11核心数据场景落地
  6. mysql数据库移植
  7. 2017 最值得关注的十大 APP、Web 界面设计趋势
  8. 使用计算机正确开机方法,电脑开关机的正确步骤
  9. android stringbuilder 一次插入多条数据_android开发面试题解析
  10. 现在去做自动化测试开发了
  11. 我从构建生产型数据库中学到的42件事
  12. 精品软件 推荐 卡巴斯基安全软件 本人使用过的效果最好的杀毒软件之一哟...
  13. Js中对URL进行转码与解码
  14. Linux 和 Windows 下实现多进程的方式以及管道操作
  15. 动态修改ViewPagerIndicator CustomTabPageIndicator Tab标签文字颜色
  16. MVPArms官方快速组件化方案开源,Android快速开发之架构组件
  17. linux majaro 安装 hp p1106打印机
  18. IEEE Transactions on Systems, Man, and Cybernetics: Systems(TSMC)投稿须知
  19. ping命令和查找计算机,ping命令查网速,电脑测网速ping命令
  20. 新经济的蛀虫——互联网大厂反腐那些事

热门文章

  1. win7QQ安装包可能被非法改动导致安装失败怎么办
  2. 《Spring实战第四版》随书源码导入Eclipse
  3. 关于appium环境搭建
  4. 卡牌大师怎么玩_LOL卡牌大师技巧 卡牌大师攻略
  5. 屏幕录制大师转换方法
  6. 什么是MIME类型?
  7. 简述数学建模的过程_数学建模
  8. ubuntu code::blocks 汉化(附汉化包)
  9. MQL5由简到繁系列一
  10. 工具 | 网络调试助手的简单使用