Android实现蓝牙聊天功能

蓝牙,时下最流行的智能设备传输数据的方式之一,通过手机app和智能设备进行连接,获取设备上的测量数据,我们生活中随处可见的比如蓝牙智能手环,蓝牙电子秤,蓝牙心电测量设备等等。

本篇我将紧接着上篇结尾所写,一起来看下手机之间如何通过蓝牙实现文字聊天。

先贴出上篇的一些demo;

当点击图上的两个列表中的任何一个列表,执行如下代码:

mBtAdapter.cancelDiscovery();
String info = ((TextView) v).getText().toString();
String address = info.substring(info.length() - 17);
Intent intent = new Intent();
intent.putExtra(EXTRA_DEVICE_ADDRESS, address);
setResult(Activity.RESULT_OK, intent);
finish();

此蓝牙聊天工具最后实现的效果是这样的:

将回到聊天主界面:

public void onActivityResult(int requestCode, int resultCode, Intent data) {
 LogUtils.getInstance().e(getClass(), "onActivityResult " + resultCode);
 switch (requestCode) {
 case REQUEST_CONNECT_DEVICE:
 // 当DeviceListActivity返回与设备连接的消息
 if (resultCode == Activity.RESULT_OK) {
 // 连接设备的MAC地址
 String address = data.getExtras().getString(
 DeviceListActivity.EXTRA_DEVICE_ADDRESS);
 // 得到蓝牙对象
 BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
 // 开始连接设备
 mChatService.connect(device);
 }
 break;
 case REQUEST_ENABLE_BT:
 // 判断蓝牙是否启用
 if (resultCode == Activity.RESULT_OK) {
 // 建立连接
 setupChat();
 } else {
 LogUtils.getInstance().e(getClass(), "蓝牙未启用");
 Toast.makeText(this, R.string.bt_not_enabled_leaving,
 Toast.LENGTH_SHORT).show();
 finish();
 }
 }
}

在此,我将重点介绍下BluetoothChatService类中的连接流程;
因为蓝牙聊天是两个手机之间进行通讯,所以他们互为主机和从机,主要思路以及步骤如下:

1.开一个线程获取socket去连接蓝牙;
2.开一个线程获监听蓝牙传入的连接,如果连接被接受的话,再开启第三个线程去处理所有传入和传出的数据;

public synchronized void connect(BluetoothDevice device) {
 if (mState == STATE_CONNECTING) {
 if (mConnectThread != null) {
 mConnectThread.cancel();
 mConnectThread = null;
 }
 }
 if (mConnectedThread != null) {
 mConnectedThread.cancel();
 mConnectedThread = null;
 }
 mConnectThread = new ConnectThread(device);
 mConnectThread.start();
 setState(STATE_CONNECTING);
}

开线程去连接

/**
 * @description:蓝牙连接线程
 * @author:zzq
 * @time: 2016-8-6 下午1:18:41
 */
private class ConnectThread extends Thread {
private final BluetoothSocket mmSocket;
private final BluetoothDevice mmDevice;
 public ConnectThread(BluetoothDevice device) {
 mmDevice = device;
 BluetoothSocket tmp = null;
 try {
 tmp = device.createRfcommSocketToServiceRecord(MY_UUID);
 } catch (IOException e) {
 LogUtils.getInstance().e(getClass(), "socket获取失败:" + e);
 }
 mmSocket = tmp;
 }
 public void run() {
 LogUtils.getInstance().e(getClass(), "开始mConnectThread");
 setName("ConnectThread");
 // mAdapter.cancelDiscovery();
 try {
 mmSocket.connect();
 } catch (IOException e) {
 // 连接失败,更新ui
 connectionFailed();
 try {
 mmSocket.close();
 } catch (IOException e2) {
 LogUtils.getInstance().e(getClass(), "关闭连接失败" + e2);
 }
 // 开启聊天接收线程
 startChat();
 return;
 }
 synchronized (BluetoothChatService.this) {
 mConnectThread = null;
 }
 connected(mmSocket, mmDevice);
 }
 public void cancel() {
 try {
 mmSocket.close();
 } catch (IOException e) {
 LogUtils.getInstance().e(getClass(), "关闭连接失败" + e);
 }
 }
}
/**
 * 监听传入的连接
 */
private class AcceptThread extends Thread {
private final BluetoothServerSocket mmServerSocket;
 public AcceptThread() {
 BluetoothServerSocket tmp = null;
 try {
 tmp = mAdapter.listenUsingRfcommWithServiceRecord(NAME, MY_UUID);
 } catch (IOException e) {
 LogUtils.getInstance().e(getClass(), "--获取socket失败:" + e);
 }
 mmServerSocket = tmp;
 }

 public void run() {
 setName("AcceptThread");
 BluetoothSocket socket = null;
 while (mState != STATE_CONNECTED) {
 LogUtils.getInstance().e(getClass(), "----accept-循环执行中-");
 try {
 socket = mmServerSocket.accept();
 } catch (IOException e) {
 LogUtils.getInstance().e(getClass(), "accept() 失败" + e);
 break;
 }
// 如果连接被接受
 if (socket != null) {
 synchronized (BluetoothChatService.this) {
 switch (mState) {
 case STATE_LISTEN:
 case STATE_CONNECTING:
 // 开始连接线程
 connected(socket, socket.getRemoteDevice());
 break;
 case STATE_NONE:
 case STATE_CONNECTED:
 // 没有准备好或已经连接
 try {
 socket.close();
 } catch (IOException e) {
 LogUtils.getInstance().e(getClass(),"不能关闭这些连接" + e);
 }
 break;

 }
 }
 }
}
 LogUtils.getInstance().e(getClass(), "结束mAcceptThread");
}

 public void cancel() {
 LogUtils.getInstance().e(getClass(), "取消 " + this);
 try {
 mmServerSocket.close();
 } catch (IOException e) {
 LogUtils.getInstance().e(getClass(), "关闭失败" + e);
 }
 }
}
/**
 * 连接成功后的线程 处理所有传入和传出的传输
 */
private class ConnectedThread extends Thread {
private final BluetoothSocket mmSocket;
private final InputStream mmInStream;
private final OutputStream mmOutStream;
 public ConnectedThread(BluetoothSocket socket) {
 mmSocket = socket;
 InputStream tmpIn = null;
 OutputStream tmpOut = null;
 // 得到BluetoothSocket输入和输出流
 try {
 tmpIn = socket.getInputStream();
 tmpOut = socket.getOutputStream();
 } catch (IOException e) {
 LogUtils.getInstance().e(getClass(),"temp sockets not created" + e);
 }
 mmInStream = tmpIn;
 mmOutStream = tmpOut;
 }
 public void run() {
 int bytes;
 String str1 = "";
 // 循环监听消息
 while (true) {
 try {
 byte[] buffer = new byte[256];
 bytes = mmInStream.read(buffer);
 String readStr = new String(buffer, 0, bytes);// 字节数组直接转换成字符串
 String str = bytes2HexString(buffer).replaceAll("00", "").trim();
 if (bytes > 0) {// 将读取到的消息发到主线程
  mHandler.obtainMessage(BluetoothChatActivity.MESSAGE_READ, bytes, -1,buffer).sendToTarget();
 } else {
  LogUtils.getInstance().e(getClass(),"disconnected");
 connectionLost();
 if (mState != STATE_NONE) {
 LogUtils.getInstance().e(getClass(), "disconnected");
startChat();
 }
 break;
 }
 } catch (IOException e) {
 LogUtils.getInstance().e(getClass(), "disconnected" + e);
 connectionLost();
 if (mState != STATE_NONE) {
 // 在重新启动监听模式启动该服务
 startChat();
 }
 break;
 }
 }
}
/**
 * 写入OutStream连接
 *
 * @param buffer
 * 要写的字节
 */
public void write(byte[] buffer) {
 try {
 mmOutStream.write(buffer);
 // 把消息传给UI
 mHandler.obtainMessage(BluetoothChatActivity.MESSAGE_WRITE, -1,-1, buffer).sendToTarget();

 } catch (IOException e) {
 LogUtils.getInstance().e(getClass(),
"Exception during write:" + e);
 }

 }
public void cancel() {
 try {
 mmSocket.close();
 } catch (IOException e) {
 LogUtils.getInstance().e(getClass(),"close() of connect socket failed:" + e);
 }
 }
 }

大概的流程就是上面三个线程里面所展现的,当然具体情况,根据项目来,比如蓝牙协议协议解析这块的根据协议定义的方式来进行解析;

代码中牵扯的到的蓝牙连接状态的改变,用到的handle,直接把状态发送至activity,通知activity更新;

 /**
 * 无法连接,通知Activity
 */
private void connectionFailed() {
 setState(STATE_LISTEN);
 Message msg = mHandler.obtainMessage(BluetoothChatActivity.MESSAGE_TOAST);
 Bundle bundle = new Bundle();
 bundle.putString(BluetoothChatActivity.TOAST, "无法连接设备");
 msg.setData(bundle);
 mHandler.sendMessage(msg);
}
/**
 * 设备断开连接,通知Activity
 */
private void connectionLost() {
 Message msg = mHandler.obtainMessage(BluetoothChatActivity.MESSAGE_TOAST);
 Bundle bundle = new Bundle();
 bundle.putString(BluetoothChatActivity.TOAST, "设备断开连接");
 msg.setData(bundle);
 mHandler.sendMessage(msg);
}

当点击发送按钮时,将文本输入框中的文字发送数据的方法:

private void sendMessage(String message) {
 if (mChatService.getState() != BluetoothChatService.STATE_CONNECTED) {
 Toast.makeText(this, R.string.not_connected,Toast.LENGTH_SHORT).show();
 return;
}
 if (message.length() > 0) {
 byte[] send = message.getBytes();
 mChatService.write(send);
 }
}
//调用BluetoothChatService类中的write进行数据发送
public void write(byte[] out) {
 ConnectedThread r;
 synchronized (this) {
 if (mState != STATE_CONNECTED)
 return;
 r = mConnectedThread;
 }
 r.write(out);
}

如此,蓝牙聊天的流程就是这样,如果退出聊天的时候,停止所有线程;

public synchronized void stop() {
 LogUtils.getInstance().e(getClass(), "---stop()");
 setState(STATE_NONE);
 if (mConnectThread != null) {
 mConnectThread.cancel();
 mConnectThread = null;
}
 if (mConnectedThread != null) {
 mConnectedThread.cancel();
 mConnectedThread = null;
}
 if (mAcceptThread != null) {
 mAcceptThread.cancel();
 mAcceptThread = null;
 }
}

相信看完本篇文章,在安卓蓝牙连接这块应该问题不大了(spp协议)。

源码地址:点我查看源码

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Android蓝牙聊天开源项目

    前言 基于Android Classic Bluetooth的蓝牙聊天软件,目前仅支持一对一实时通信.文件传输.好友添加.好友分组.好友在线状态更新等功能,其中消息发送支持文本.表情等方式. 项目地址:Android蓝牙聊天项目 前景 蓝牙技术作为一种小范围无线连接技术,能够在设备间实现方便快捷.灵活安全.低成本.低功耗的数据和语音通信,是目前实现无线个人局域网的主流技术之一.同时,蓝牙系统以自组式组网的方式工作,每个蓝牙设备都可以在网络中实现路由选择的功能,可以形成移动自组网络.蓝牙的特性在许

  • Android实现一对一蓝牙聊天APP

    学习了,三天的Android 蓝牙开发,开始是一头雾水,看着别人讲的Google官方的demo感觉很容易,所有自己也尝试写一个很简单的聊天demo.可是想的很简单,自己做起来也花了,将近一天的时间才搞定这个基本的流程设计.下面是几点心得后面再贴代码 1)写一个简单的demo也好,记得一定需要有总体的流程,才开始抠代码 2)既然是demo毕竟就是新的知识,代码中间的log点一定\不能少,这是你快速调试的利器 3)还是thinking in java 里面的那句话,思考什么是可变的,什么是不可变的,

  • android实现主动连接和被动连接的蓝牙聊天功能

    在项目中经常用到蓝牙的应用,在这里特意写了一个demo.并且封装了代码,可以主动连接和被动连接一起使用,也可以分开使用.方便后面以后查询使用,也重新踩了部分坑. 项目地址:android实现蓝牙聊天功能 1.程序简单的界面 2.客户端,主动连接 package com.bluetooth.tool; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android

  • Android实现蓝牙聊天功能

    蓝牙,时下最流行的智能设备传输数据的方式之一,通过手机app和智能设备进行连接,获取设备上的测量数据,我们生活中随处可见的比如蓝牙智能手环,蓝牙电子秤,蓝牙心电测量设备等等. 本篇我将紧接着上篇结尾所写,一起来看下手机之间如何通过蓝牙实现文字聊天. 先贴出上篇的一些demo: 当点击图上的两个列表中的任何一个列表,执行如下代码: mBtAdapter.cancelDiscovery(); String info = ((TextView) v).getText().toString(); Str

  • Android在类微信程序中实现蓝牙聊天功能的示例代码

    项目要求 1.初次打开程序时右上角标题栏显示"无连接",点击旁边的按钮选择"我的好友",进入配对界面: 2.选择好友之后,返回主界面,标题栏会显示已连接的手机型号: 3.两部手机间可通过蓝牙聊天 效果展示 项目结构 主要代码 1.在清单文件中注册权限 <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /> <uses-permission and

  • Android仿微信语音聊天功能

    本文实例讲述了Android仿微信语音聊天功能代码.分享给大家供大家参考.具体如下: 项目效果如下: 具体代码如下: AudioManager.java package com.xuliugen.weichat; import java.io.File; import java.io.IOException; import java.util.UUID; import android.media.MediaRecorder; public class AudioManager { private

  • Android 取消蓝牙配对框实现自动配对功能

    我看了几个文章,主要是接受配对广播,然后设置pin,实现配对,但是网上的大部分手机是不可以的,Android.bluetoothdevice 下 action_pair_request ,没有定义这个,开始困扰了我一点时间,实现难度:是否能进入那个广播响应 定义了一个类,这个是网上的可以直接用 package zicox.esc; import java.lang.reflect.Method; import java.lang.reflect.Field; import android.blu

  • android Socket实现简单聊天功能以及文件传输

    干程序是一件枯燥重复的事,每当感到内心浮躁的时候,我就会找小说来看.我从小就喜爱看武侠小说,一直有着武侠梦.从金庸,古龙,梁羽生系列到凤歌(昆仑),孙晓(英雄志)以及萧鼎的(诛仙)让我领略着不一样的江湖. 如果你有好看的武侠系列小说,给我留言哦.题外话就扯这么多了,接着还是上技术. 看看今天实现的功能效果图: 可以这里使用多台手机进行通讯,我采用的服务器发送消息. 是不是只有发送消息,有些显得太单调了.好,在发送消息的基础上增加文件传输.后期会增加视频,音频的传输,增加表情包.那一起来看看图文消

  • 基于Socket.IO实现Android聊天功能代码示例

    一.简述 Socket.IO是一个完全由JavaScript实现.基于Node.js.支持WebSocket的协议用于实时通信.跨平台的开源框架,它包括了客户端的JavaScript和服务器端的Node.js. 该种官方介绍看起来有点懵逼,简而言之就是:客户端可通过Socket.IO与服务器建立实时通信管道 二.应用 该下就是介绍Socket.IO通信管道的铺设.通信以及销毁工作. 2.1 引入Socket.io包 compile 'io.socket:socket.io-client:0.8.

  • Android 获取蓝牙Mac地址的正确方法

    android 从6.0开始,通过BluetoothAdapter.getDefaultAdapter().getAddress()获取的地址是一个固定值02:00:00:00:00:00.6.0已经对蓝牙Wi-Fi的MAC地址做了隐藏. 以下方法能正确的获取android自带蓝牙的Mac地址: 1.添加net.vidageek:mirror:1.6.1 2.实现过程 本人也尝试过其他方法获取,比如从cat /sys/class/net/wlan0/address 或者/sys/class/ne

随机推荐