热门标签 | 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


推荐阅读
  • 本文介绍了使用cacti监控mssql 2005运行资源情况的操作步骤,包括安装必要的工具和驱动,测试mssql的连接,配置监控脚本等。通过php连接mssql来获取SQL 2005性能计算器的值,实现对mssql的监控。详细的操作步骤和代码请参考附件。 ... [详细]
  • Skywalking系列博客1安装单机版 Skywalking的快速安装方法
    本文介绍了如何快速安装单机版的Skywalking,包括下载、环境需求和端口检查等步骤。同时提供了百度盘下载地址和查询端口是否被占用的命令。 ... [详细]
  • 本文介绍了在rhel5.5操作系统下搭建网关+LAMP+postfix+dhcp的步骤和配置方法。通过配置dhcp自动分配ip、实现外网访问公司网站、内网收发邮件、内网上网以及SNAT转换等功能。详细介绍了安装dhcp和配置相关文件的步骤,并提供了相关的命令和配置示例。 ... [详细]
  • Nginx使用(server参数配置)
    本文介绍了Nginx的使用,重点讲解了server参数配置,包括端口号、主机名、根目录等内容。同时,还介绍了Nginx的反向代理功能。 ... [详细]
  • android listview OnItemClickListener失效原因
    最近在做listview时发现OnItemClickListener失效的问题,经过查找发现是因为button的原因。不仅listitem中存在button会影响OnItemClickListener事件的失效,还会导致单击后listview每个item的背景改变,使得item中的所有有关焦点的事件都失效。本文给出了一个范例来说明这种情况,并提供了解决方法。 ... [详细]
  • 如何使用Java获取服务器硬件信息和磁盘负载率
    本文介绍了使用Java编程语言获取服务器硬件信息和磁盘负载率的方法。首先在远程服务器上搭建一个支持服务端语言的HTTP服务,并获取服务器的磁盘信息,并将结果输出。然后在本地使用JS编写一个AJAX脚本,远程请求服务端的程序,得到结果并展示给用户。其中还介绍了如何提取硬盘序列号的方法。 ... [详细]
  • 计算机存储系统的层次结构及其优势
    本文介绍了计算机存储系统的层次结构,包括高速缓存、主存储器和辅助存储器三个层次。通过分层存储数据可以提高程序的执行效率。计算机存储系统的层次结构将各种不同存储容量、存取速度和价格的存储器有机组合成整体,形成可寻址存储空间比主存储器空间大得多的存储整体。由于辅助存储器容量大、价格低,使得整体存储系统的平均价格降低。同时,高速缓存的存取速度可以和CPU的工作速度相匹配,进一步提高程序执行效率。 ... [详细]
  • Android开发实现的计时器功能示例
    本文分享了Android开发实现的计时器功能示例,包括效果图、布局和按钮的使用。通过使用Chronometer控件,可以实现计时器功能。该示例适用于Android平台,供开发者参考。 ... [详细]
  • Ihavethefollowingonhtml我在html上有以下内容<html><head><scriptsrc..3003_Tes ... [详细]
  • 本文讨论了如何使用Web.Config进行自定义配置节的配置转换。作者提到,他将msbuild设置为详细模式,但转换却忽略了带有替换转换的自定义部分的存在。 ... [详细]
  • 本文由编程笔记#小编整理,主要介绍了关于数论相关的知识,包括数论的算法和百度百科的链接。文章还介绍了欧几里得算法、辗转相除法、gcd、lcm和扩展欧几里得算法的使用方法。此外,文章还提到了数论在求解不定方程、模线性方程和乘法逆元方面的应用。摘要长度:184字。 ... [详细]
  • 使用圣杯布局模式实现网站首页的内容布局
    本文介绍了使用圣杯布局模式实现网站首页的内容布局的方法,包括HTML部分代码和实例。同时还提供了公司新闻、最新产品、关于我们、联系我们等页面的布局示例。商品展示区包括了车里子和农家生态土鸡蛋等产品的价格信息。 ... [详细]
  • Nginx使用AWStats日志分析的步骤及注意事项
    本文介绍了在Centos7操作系统上使用Nginx和AWStats进行日志分析的步骤和注意事项。通过AWStats可以统计网站的访问量、IP地址、操作系统、浏览器等信息,并提供精确到每月、每日、每小时的数据。在部署AWStats之前需要确认服务器上已经安装了Perl环境,并进行DNS解析。 ... [详细]
  • 本文介绍了Python爬虫技术基础篇面向对象高级编程(中)中的多重继承概念。通过继承,子类可以扩展父类的功能。文章以动物类层次的设计为例,讨论了按照不同分类方式设计类层次的复杂性和多重继承的优势。最后给出了哺乳动物和鸟类的设计示例,以及能跑、能飞、宠物类和非宠物类的增加对类数量的影响。 ... [详细]
  • 本文介绍了Oracle存储过程的基本语法和写法示例,同时还介绍了已命名的系统异常的产生原因。 ... [详细]
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社区 版权所有