热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

AndroidBLE与终端通信(三)——客户端与服务端通信过程以及实现数据通信

AndroidBLE与终端通信(三)——客户端与服务端通信过程以及实现数据通信前面的终究只是小知识点,上不了台面,也只能算是

Android BLE与终端通信(三)——客户端与服务端通信过程以及实现数据通信




前面的终究只是小知识点,上不了台面,也只能算是起到一个科普的作用,而同步到实际的开发上去,今天就来延续前两篇实现蓝牙主从关系的客户端和服务端了,本文相关链接需要去google的API上查看,需要翻墙的


Bluetooth Low Energy:http://developer.android.com/guide/topics/connectivity/bluetooth-le.html


但是我们依然没有讲到BLE(低功耗蓝牙),放心,下一篇就回讲到,跟前面的基本上很大的不同,我们今天来看下客户端和服务端的实现

我们以上篇为栗子:
Android BLE与终端通信(二)——Android Bluetooth基础搜索蓝牙设备显示列表



一.蓝牙数据传输


蓝牙数据传输其实跟我们的 Socket(套接字)有点类似,如果有不懂的,可以百度一下概念,我们只要知道是这么回事就可以了,在网络中使用Socket和ServerSocket控制客户端和服务端来数据读写。而蓝牙通讯也是由客户端和服务端来完成的,蓝牙客户端Socket是BluetoothSocket,蓝牙服务端Socket是BluetoothServerSocket,这两个类都在android.bluetooth包下,而且无论是BluetoothSocket还是BluetoothServerSocket,我们都需要一个UUID(标识符),这个UUID在上篇也是有提到,而且他的格式也是固定的:



UUID:XXXXXXXX(8)-XXXX(4)-XXXX(4)-XXXX(4)-XXXXXXXXXXXX(12)


第一段是8位,中间三段式4位,最后一段是12位,UUID相当于Socket的端口,而蓝牙地址则相当于Socket的IP



1.activity_main.xml

<LinearLayout xmlns:android&#61;"http://schemas.android.com/apk/res/android"xmlns:tools&#61;"http://schemas.android.com/tools"android:layout_width&#61;"match_parent"android:layout_height&#61;"match_parent"android:orientation&#61;"vertical" ><Button
android:layout_width&#61;"match_parent"android:layout_height&#61;"wrap_content"android:onClick&#61;"btnSearch"android:text&#61;"搜索蓝牙设备" />
<ListView
android:id&#61;"&#64;&#43;id/lvDevices"android:layout_width&#61;"match_parent"android:layout_height&#61;"0dp"android:layout_weight&#61;"1" />
LinearLayout>

2.实现步骤


1.声明

我们需要的东西

// 本地蓝牙适配器private BluetoothAdapter mBluetoothAdapter;// 列表private ListView lvDevices;// 存储搜索到的蓝牙private List bluetoothDevices &#61; new ArrayList();// listview的adapterprivate ArrayAdapter arrayAdapter;// UUID.randomUUID()随机获取UUIDprivate final UUID MY_UUID &#61; UUID.fromString("db764ac8-4b08-7f25-aafe-59d03c27bae3");// 连接对象的名称private final String NAME &#61; "LGL";// 这里本身即是服务端也是客户端&#xff0c;需要如下类private BluetoothSocket clientSocket;private BluetoothDevice device;// 输出流_客户端需要往服务端输出private OutputStream os;

2.初始化

// 获取本地蓝牙适配器mBluetoothAdapter &#61; BluetoothAdapter.getDefaultAdapter();// 判断手机是否支持蓝牙if (mBluetoothAdapter &#61;&#61; null) {Toast.makeText(this, "设备不支持蓝牙", Toast.LENGTH_SHORT).show();finish();}// 判断是否打开蓝牙if (!mBluetoothAdapter.isEnabled()) {// 弹出对话框提示用户是后打开Intent intent &#61; new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);startActivityForResult(intent, 1);// 不做提示&#xff0c;强行打开// mBluetoothAdapter.enable();}// 初始化listviewlvDevices &#61; (ListView) findViewById(R.id.lvDevices);lvDevices.setOnItemClickListener(this);// 获取已经配对的设备Set pairedDevices &#61; mBluetoothAdapter.getBondedDevices();// 判断是否有配对过的设备if (pairedDevices.size() > 0) {for (BluetoothDevice device : pairedDevices) {// 遍历到列表中bluetoothDevices.add(device.getName() &#43; ":"&#43; device.getAddress() &#43; "\n");}}// adapterarrayAdapter &#61; new ArrayAdapter(this,android.R.layout.simple_list_item_1, android.R.id.text1,bluetoothDevices);lvDevices.setAdapter(arrayAdapter);/*** 异步搜索蓝牙设备——广播接收*/// 找到设备的广播IntentFilter filter &#61; new IntentFilter(BluetoothDevice.ACTION_FOUND);// 注册广播registerReceiver(receiver, filter);// 搜索完成的广播filter &#61; new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);// 注册广播registerReceiver(receiver, filter);}

3.点击搜索

public void btnSearch(View v) {// 设置进度条setProgressBarIndeterminateVisibility(true);setTitle("正在搜索...");// 判断是否在搜索,如果在搜索&#xff0c;就取消搜索if (mBluetoothAdapter.isDiscovering()) {mBluetoothAdapter.cancelDiscovery();}// 开始搜索mBluetoothAdapter.startDiscovery();}

4.搜索设备

private final BroadcastReceiver receiver &#61; new BroadcastReceiver() {&#64;Overridepublic void onReceive(Context context, Intent intent) {// 收到的广播类型String action &#61; intent.getAction();// 发现设备的广播if (BluetoothDevice.ACTION_FOUND.equals(action)) {// 从intent中获取设备BluetoothDevice device &#61; intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);// 判断是否配对过if (device.getBondState() !&#61; BluetoothDevice.BOND_BONDED) {// 添加到列表bluetoothDevices.add(device.getName() &#43; ":"&#43; device.getAddress() &#43; "\n");arrayAdapter.notifyDataSetChanged();}// 搜索完成} else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) {// 关闭进度条setProgressBarIndeterminateVisibility(true);setTitle("搜索完成&#xff01;");}}};

5.客户端实现已经发送数据流

// 客户端&#64;Overridepublic void onItemClick(AdapterView parent, View view, int position,long id) {// 先获得蓝牙的地址和设备名String s &#61; arrayAdapter.getItem(position);// 单独解析地址String address &#61; s.substring(s.indexOf(":") &#43; 1).trim();// 主动连接蓝牙try {// 判断是否在搜索,如果在搜索&#xff0c;就取消搜索if (mBluetoothAdapter.isDiscovering()) {mBluetoothAdapter.cancelDiscovery();}try {// 判断是否可以获得if (device &#61;&#61; null) {// 获得远程设备device &#61; mBluetoothAdapter.getRemoteDevice(address);}// 开始连接if (clientSocket &#61;&#61; null) {clientSocket &#61; device.createRfcommSocketToServiceRecord(MY_UUID);// 连接clientSocket.connect();// 获得输出流os &#61; clientSocket.getOutputStream();}} catch (Exception e) {// TODO: handle exception}// 如果成功获得输出流if (os !&#61; null) {os.write("Hello Bluetooth!".getBytes("utf-8"));}} catch (Exception e) {// TODO: handle exception}}

6.Handler服务

// 服务端&#xff0c;需要监听客户端的线程类private Handler handler &#61; new Handler() {public void handleMessage(android.os.Message msg) {Toast.makeText(MainActivity.this, String.valueOf(msg.obj),Toast.LENGTH_SHORT).show();super.handleMessage(msg);}};

7.服务端读取数据流

// 线程服务类private class AcceptThread extends Thread {private BluetoothServerSocket serverSocket;private BluetoothSocket socket;// 输入 输出流private OutputStream os;private InputStream is;public AcceptThread() {try {serverSocket &#61; mBluetoothAdapter.listenUsingRfcommWithServiceRecord(NAME, MY_UUID);} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}&#64;Overridepublic void run() {// 截获客户端的蓝牙消息try {socket &#61; serverSocket.accept(); // 如果阻塞了&#xff0c;就会一直停留在这里is &#61; socket.getInputStream();os &#61; socket.getOutputStream();// 不断接收请求,如果客户端没有发送的话还是会阻塞while (true) {// 每次只发送128个字节byte[] buffer &#61; new byte[128];// 读取int count &#61; is.read();// 如果读取到了&#xff0c;我们就发送刚才的那个ToastMessage msg &#61; new Message();msg.obj &#61; new String(buffer, 0, count, "utf-8");handler.sendMessage(msg);}} catch (Exception e) {// TODO: handle exception}}}

8.开启服务

首先要声明

//启动服务ac &#61; new AcceptThread();ac.start();

MainActivity完整代码

package com.lgl.bluetoothget;import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.UUID;import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothServerSocket;
import android.bluetooth.BluetoothSocket;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;public class MainActivity extends Activity implements OnItemClickListener {// 本地蓝牙适配器private BluetoothAdapter mBluetoothAdapter;// 列表private ListView lvDevices;// 存储搜索到的蓝牙private List bluetoothDevices &#61; new ArrayList();// listview的adapterprivate ArrayAdapter arrayAdapter;// UUID.randomUUID()随机获取UUIDprivate final UUID MY_UUID &#61; UUID.fromString("db764ac8-4b08-7f25-aafe-59d03c27bae3");// 连接对象的名称private final String NAME &#61; "LGL";// 这里本身即是服务端也是客户端&#xff0c;需要如下类private BluetoothSocket clientSocket;private BluetoothDevice device;// 输出流_客户端需要往服务端输出private OutputStream os;//线程类的实例private AcceptThread ac;&#64;Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);initView();}private void initView() {// 获取本地蓝牙适配器mBluetoothAdapter &#61; BluetoothAdapter.getDefaultAdapter();// 判断手机是否支持蓝牙if (mBluetoothAdapter &#61;&#61; null) {Toast.makeText(this, "设备不支持蓝牙", Toast.LENGTH_SHORT).show();finish();}// 判断是否打开蓝牙if (!mBluetoothAdapter.isEnabled()) {// 弹出对话框提示用户是后打开Intent intent &#61; new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);startActivityForResult(intent, 1);// 不做提示&#xff0c;强行打开// mBluetoothAdapter.enable();}// 初始化listviewlvDevices &#61; (ListView) findViewById(R.id.lvDevices);lvDevices.setOnItemClickListener(this);// 获取已经配对的设备Set pairedDevices &#61; mBluetoothAdapter.getBondedDevices();// 判断是否有配对过的设备if (pairedDevices.size() > 0) {for (BluetoothDevice device : pairedDevices) {// 遍历到列表中bluetoothDevices.add(device.getName() &#43; ":"&#43; device.getAddress() &#43; "\n");}}// adapterarrayAdapter &#61; new ArrayAdapter(this,android.R.layout.simple_list_item_1, android.R.id.text1,bluetoothDevices);lvDevices.setAdapter(arrayAdapter);//启动服务ac &#61; new AcceptThread();ac.start();/*** 异步搜索蓝牙设备——广播接收*/// 找到设备的广播IntentFilter filter &#61; new IntentFilter(BluetoothDevice.ACTION_FOUND);// 注册广播registerReceiver(receiver, filter);// 搜索完成的广播filter &#61; new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);// 注册广播registerReceiver(receiver, filter);}public void btnSearch(View v) {// 设置进度条setProgressBarIndeterminateVisibility(true);setTitle("正在搜索...");// 判断是否在搜索,如果在搜索&#xff0c;就取消搜索if (mBluetoothAdapter.isDiscovering()) {mBluetoothAdapter.cancelDiscovery();}// 开始搜索mBluetoothAdapter.startDiscovery();}// 广播接收器private final BroadcastReceiver receiver &#61; new BroadcastReceiver() {&#64;Overridepublic void onReceive(Context context, Intent intent) {// 收到的广播类型String action &#61; intent.getAction();// 发现设备的广播if (BluetoothDevice.ACTION_FOUND.equals(action)) {// 从intent中获取设备BluetoothDevice device &#61; intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);// 判断是否配对过if (device.getBondState() !&#61; BluetoothDevice.BOND_BONDED) {// 添加到列表bluetoothDevices.add(device.getName() &#43; ":"&#43; device.getAddress() &#43; "\n");arrayAdapter.notifyDataSetChanged();}// 搜索完成} else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) {// 关闭进度条setProgressBarIndeterminateVisibility(true);setTitle("搜索完成&#xff01;");}}};// 客户端&#64;Overridepublic void onItemClick(AdapterView parent, View view, int position,long id) {// 先获得蓝牙的地址和设备名String s &#61; arrayAdapter.getItem(position);// 单独解析地址String address &#61; s.substring(s.indexOf(":") &#43; 1).trim();// 主动连接蓝牙try {// 判断是否在搜索,如果在搜索&#xff0c;就取消搜索if (mBluetoothAdapter.isDiscovering()) {mBluetoothAdapter.cancelDiscovery();}try {// 判断是否可以获得if (device &#61;&#61; null) {// 获得远程设备device &#61; mBluetoothAdapter.getRemoteDevice(address);}// 开始连接if (clientSocket &#61;&#61; null) {clientSocket &#61; device.createRfcommSocketToServiceRecord(MY_UUID);// 连接clientSocket.connect();// 获得输出流os &#61; clientSocket.getOutputStream();}} catch (Exception e) {// TODO: handle exception}// 如果成功获得输出流if (os !&#61; null) {os.write("Hello Bluetooth!".getBytes("utf-8"));}} catch (Exception e) {// TODO: handle exception}}// 服务端&#xff0c;需要监听客户端的线程类private Handler handler &#61; new Handler() {public void handleMessage(android.os.Message msg) {Toast.makeText(MainActivity.this, String.valueOf(msg.obj),Toast.LENGTH_SHORT).show();super.handleMessage(msg);}};// 线程服务类private class AcceptThread extends Thread {private BluetoothServerSocket serverSocket;private BluetoothSocket socket;// 输入 输出流private OutputStream os;private InputStream is;public AcceptThread() {try {serverSocket &#61; mBluetoothAdapter.listenUsingRfcommWithServiceRecord(NAME, MY_UUID);} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}&#64;Overridepublic void run() {// 截获客户端的蓝牙消息try {socket &#61; serverSocket.accept(); // 如果阻塞了&#xff0c;就会一直停留在这里is &#61; socket.getInputStream();os &#61; socket.getOutputStream();// 不断接收请求,如果客户端没有发送的话还是会阻塞while (true) {// 每次只发送128个字节byte[] buffer &#61; new byte[128];// 读取int count &#61; is.read();// 如果读取到了&#xff0c;我们就发送刚才的那个ToastMessage msg &#61; new Message();msg.obj &#61; new String(buffer, 0, count, "utf-8");handler.sendMessage(msg);}} catch (Exception e) {// TODO: handle exception}}}
}

Google的API上其实已经说的很详细了的&#xff0c;这里我再提供一份PDF学习文档&#xff0c;可以更加直观的了解


PDF文档下载地址&#xff1a;http://download.csdn.net/detail/qq_26787115/9416162


Demo下载地址&#xff1a;http://download.csdn.net/detail/qq_26787115/9416158


推荐阅读
  • 本文探讨了资源访问的学习路径与方法,旨在帮助学习者更高效地获取和利用各类资源。通过分析不同资源的特点和应用场景,提出了多种实用的学习策略和技术手段,为学习者提供了系统的指导和建议。 ... [详细]
  • 本文介绍了如何利用Struts1框架构建一个简易的四则运算计算器。通过采用DispatchAction来处理不同类型的计算请求,并使用动态Form来优化开发流程,确保代码的简洁性和可维护性。同时,系统提供了用户友好的错误提示,以增强用户体验。 ... [详细]
  • 本文探讨了利用Java实现WebSocket实时消息推送技术的方法。与传统的轮询、长连接或短连接等方案相比,WebSocket提供了一种更为高效和低延迟的双向通信机制。通过建立持久连接,服务器能够主动向客户端推送数据,从而实现真正的实时消息传递。此外,本文还介绍了WebSocket在实际应用中的优势和应用场景,并提供了详细的实现步骤和技术细节。 ... [详细]
  • 掌握Android UI设计:利用ZoomControls实现图片缩放功能
    本文介绍了如何在Android应用中通过使用ZoomControls组件来实现图片的缩放功能。ZoomControls提供了一种简单且直观的方式,让用户可以通过点击放大和缩小按钮来调整图片的显示大小。文章详细讲解了ZoomControls的基本用法、布局设置以及与ImageView的结合使用方法,适合初学者快速掌握Android UI设计中的这一重要功能。 ... [详细]
  • 您的数据库配置是否安全?DBSAT工具助您一臂之力!
    本文探讨了Oracle提供的免费工具DBSAT,该工具能够有效协助用户检测和优化数据库配置的安全性。通过全面的分析和报告,DBSAT帮助用户识别潜在的安全漏洞,并提供针对性的改进建议,确保数据库系统的稳定性和安全性。 ... [详细]
  • 本文介绍了一种自定义的Android圆形进度条视图,支持在进度条上显示数字,并在圆心位置展示文字内容。通过自定义绘图和组件组合的方式实现,详细展示了自定义View的开发流程和关键技术点。示例代码和效果展示将在文章末尾提供。 ... [详细]
  • ButterKnife 是一款用于 Android 开发的注解库,主要用于简化视图和事件绑定。本文详细介绍了 ButterKnife 的基础用法,包括如何通过注解实现字段和方法的绑定,以及在实际项目中的应用示例。此外,文章还提到了截至 2016 年 4 月 29 日,ButterKnife 的最新版本为 8.0.1,为开发者提供了最新的功能和性能优化。 ... [详细]
  • 尽管我们尽最大努力,任何软件开发过程中都难免会出现缺陷。为了更有效地提升对支持部门的协助与支撑,本文探讨了多种策略和最佳实践,旨在通过改进沟通、增强培训和支持流程来减少这些缺陷的影响,并提高整体服务质量和客户满意度。 ... [详细]
  • 技术分享:深入解析GestureDetector手势识别机制
    技术分享:深入解析GestureDetector手势识别机制 ... [详细]
  • 在过去,我曾使用过自建MySQL服务器中的MyISAM和InnoDB存储引擎(也曾尝试过Memory引擎)。今年初,我开始转向阿里云的关系型数据库服务,并深入研究了其高效的压缩存储引擎TokuDB。TokuDB在数据压缩和处理大规模数据集方面表现出色,显著提升了存储效率和查询性能。通过实际应用,我发现TokuDB不仅能够有效减少存储成本,还能显著提高数据处理速度,特别适用于高并发和大数据量的场景。 ... [详细]
  • 在尝试对从复杂 XSD 生成的类进行序列化时,遇到了 `NullReferenceException` 错误。尽管已经花费了数小时进行调试和搜索相关资料,但仍然无法找到问题的根源。希望社区能够提供一些指导和建议,帮助解决这一难题。 ... [详细]
  • 深入解析 Android 选择器与形状绘制技术
    本文深入探讨了 Android 中选择器(Selector)与形状绘制(Shape Drawing)技术的应用与实现。重点分析了 `Selector` 的 `item` 元素,其中包括 `android:drawable` 属性的使用方法及其在不同状态下的表现。此外,还详细介绍了如何通过 XML 定义复杂的形状和渐变效果,以提升 UI 设计的灵活性和美观性。 ... [详细]
  • Android 图像色彩处理技术详解
    本文详细探讨了 Android 平台上的图像色彩处理技术,重点介绍了如何通过模仿美图秀秀的交互方式,利用 SeekBar 实现对图片颜色的精细调整。文章展示了具体的布局设计和代码实现,帮助开发者更好地理解和应用图像处理技术。 ... [详细]
  • Spring框架入门指南:专为新手打造的详细学习笔记
    Spring框架是Java Web开发中广泛应用的轻量级应用框架,以其卓越的功能和出色的性能赢得了广大开发者的青睐。本文为初学者提供了详尽的学习指南,涵盖基础概念、核心组件及实际应用案例,帮助新手快速掌握Spring框架的核心技术与实践技巧。 ... [详细]
  • 本文探讨了在Android应用中实现动态滚动文本显示控件的优化方法。通过详细分析焦点管理机制,特别是通过设置返回值为`true`来确保焦点不会被其他控件抢占,从而提升滚动文本的流畅性和用户体验。具体实现中,对`MarqueeText.java`进行了代码层面的优化,增强了控件的稳定性和兼容性。 ... [详细]
author-avatar
Hoorxx鹿_416
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有