蓝牙(简单的通信连接)

蓝牙是什么(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定位权限那别人都说只加一个就好了 我的貌似不行 所以我就都加上了>

<!-- 蓝牙通讯权限 -->
    <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();
                 mPeiDuiList.clear();
                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();//停止聊天
    }

猜你喜欢

转载自blog.csdn.net/qq_42259105/article/details/82748803