Android API Guides---Bluetooth

Bluetooth

Android平台包含蓝牙网络协议栈,它同意设备以无线方式与其他蓝牙设备进行数据交换的支持。应用程序框架提供了訪问通过Android蓝牙API的蓝牙功能。这些API使应用程序无线方式连接到其他蓝牙设备,实现点对点和多点无线功能。


使用蓝牙的API。Android应用程序能够运行下面操作:


扫描其它蓝牙设备
查询本地蓝牙适配器配对的蓝牙设备
建立RFCOMM通道
连接到通过服务发现其它设备
传送数据和从其它设备
管理多个连接
本文介绍怎样使用传统蓝牙。经典蓝牙是有关电池密集型操作,如流媒体和Android设备之间的通信是正确的选择。对于低功耗的要求蓝牙设备的Andr​​oid 4.3(API等级18)引入了低功耗蓝牙API支持。要了解很多其它信息,请參阅蓝牙低功耗。


基础


本文介绍了怎样使用Android的蓝牙API来完毕必要的四大任务。使用蓝牙通信:建立蓝牙,发现要么在当地配对或可用,连接设备的设备和设备之间的传输数据。




全部蓝牙API都是在android.bluetooth封装。这里有您须要创建蓝牙连接的类和接口的摘要:


BluetoothAdapter
代表本地蓝牙适配器(蓝牙无线电)。该BluetoothAdapter是入口点全部蓝牙互动。利用这一点。你会发现其它蓝牙设备,查询保税(配对)的设备列表,使用已知的MAC地址实例化一个BluetoothDevice类,并创建一个BluetoothServerSocket监听来自其它设备的通信。
BluetoothDevice类
表示远程蓝牙设备。使用这个请求通过绕装置的BluetoothSocket或查询的信息与远程设备的连接。如它的名称,地址,类别。和结合状态。
的BluetoothSocket
表示为蓝牙套接字接口(类似于TCP插座)。这是连接点,它同意应用程序通过InputStream和OutputStream其他蓝牙设备交换数据。
BluetoothServerSocket
表示侦听传入请求(类似于TCP ServerSocket的)一个开放的server套接字。

为了连接两个Android设备。一台设备必须打开这个类的server套接字。当一个远程蓝牙设备建立连接请求到该装置中。当连接被接受的BluetoothServerSocket将返回一个连接的BluetoothSocket。
BluetoothClass
描写叙述的一般特征和蓝牙设备的能力。

这是一个仅仅读设置定义设备的主要和次要设备类和它的服务性质。可是。这并不能可靠地描写叙述了设备支持的全部蓝牙配置文件和服务,并且是作为一个提示设备类型很实用。
BluetoothProfile
表示蓝牙配置文件的接口。

蓝牙配置文件是设备间基于蓝牙的通信的无线接口规范。

一个样例是免提模式。对于配置文件的具体讨论。请參阅使用配置文件
蓝牙耳机
蓝牙耳机提供了支持。与手机一起使用。这包含蓝牙耳机和免提(V1.5)型材。
BluetoothA2dp
怎样定义高品质音频,可从流一个设备到还有一个通过蓝牙连接。 “A2DP”代表高级音频传输模式。
BluetoothHealth
表示控制蓝牙服务医疗设备规范代理。
BluetoothHealthCallback
您用来实现BluetoothHealth回调的一个抽象类。

您必须扩展这个类,并实现回调方法来接收有关在应用程序的注冊状态和蓝牙信道状态的变化更新。
BluetoothHealthAppConfiguration
表示蓝牙医疗第三方应用注冊与远程蓝牙设备的健康通信的应用程序配置。


BluetoothProfile.ServiceListener
该通知时,他们已经被连接到或从服务断开BluetoothProfile的IPCclient的接口(即。执行一个特定的轮廓内部服务)。
蓝牙权限


为了使用应用程序中的蓝牙功能。您必须声明蓝牙权限蓝牙。你须要这个权限才干运行不论什么蓝牙通信。比方请求连接,接受连接。数据传输。


假设你希望你的应用程序来启动设备发现或操纵蓝牙设置,您还必须声明BLUETOOTH_ADMIN许可。大多数应用程序须要这个权限仅用于发现本地的蓝牙设备的能力。

通过此权限授予其它的能力不应该被使用,除非应用程序是一个“电源管理”,将依据用户的请求改动蓝牙设置。注:假设您使用BLUETOOTH_ADMIN许可。则还必须具备蓝牙权限。




声明在您的应用程序清单文件的蓝牙权限(S)。比如:

 
<manifest ... >
  <uses-permission android:name="android.permission.BLUETOOTH" />
  ...
</manifest>
请參阅有关声明应用程序权限的具体信息<使用许可权>引用。
设置蓝牙
图1:启用蓝牙对话框。
在应用程序可以通过蓝牙通信,您须要验证支持蓝牙设备上。假设是这样。请确保它已启用。
假设不支持蓝牙。那么你应该优雅地禁用不论什么蓝牙功能。

假设支持蓝牙,但被禁用。则能够要求用户启用蓝牙无需离开应用程序。这样的设置两个步骤来完毕,使用BluetoothAdapter。


获取BluetoothAdapter
该BluetoothAdapter须要的不论什么和全部蓝牙活动。要获得BluetoothAdapter,调用静态getDefaultAdapter()方法。

返回表示设备自身的蓝牙适配器(蓝牙无线电)一BluetoothAdapter。另一个蓝牙适配器为整个系统和应用程序能够使用这个对象与它进行交互。假设getDefaultAdapter()返回null,则该设备不支持蓝牙和你的故事在这里结束。比如:

BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (mBluetoothAdapter == null) {
    // Device does not support Bluetooth
}
启用蓝牙
接下来。您须要确保蓝牙已启用。调用isEnabled()检查蓝牙当前是否启用。假设此方法返回false,那么蓝牙被禁用。要请求蓝牙启用,调用startActivityForResult()与ACTION_REQUEST_ENABLE行动意图。这将发出一个请求通过系统设置来启用蓝牙(无需停止应用程序)。 比如:

 
if (!mBluetoothAdapter.isEnabled()) {
    Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
    startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
}
将出现一个对话框。要求用户权限才干启用蓝牙功能,如图1。

假设用户回答“是”,系统将開始启用蓝牙,一旦该过程完毕后(或失败),焦点将返回到应用程序。
)传递给startActivityForResult(该REQUEST_ENABLE_BT常量是一个本地定义整数(必须大于0更大)。系统传回在你的onActivityResult()实现为requestCode參数。
假设启用蓝牙成功,你的活动收到了的onActivityResult()回调RESULT_OK结果代码。

假设蓝牙没有因为启用错误(或用户回答“否”),那么结果代码RESULT_CANCELED。


或者,您的应用程序还能够侦听广播ACTION_STATE_CHANGED意图。这每当蓝牙状态发生变化,系统将播出。此广播包括了额外的字段EXTRA_STATE和EXTRA曾经的状态,包括新老蓝牙状态。分别为。这些额外的字段可能的值是STATE_TURNING_ON,STATE_ON,STATE_TURNING_OFF和STATE_OFF。侦听此广播能够检測到您的应用程序正在执行,而蓝牙状态所做的更改很实用。
提示:启用可发现会自己主动启用蓝牙。假设您计划运行蓝牙活动前始终使设备可发现。你能够跳过上面的步骤2。阅读关于启用可发现,下文。


查找设备
使用BluetoothAdapter。能够发现不管是通过设备发现,或通过查询配对(保税)的设备列表远程蓝牙设备。
设备发现的是,搜索蓝牙设备的局部区域​​,然后请求关于每个的一些信息(这有时被称为“发现”。“查询”或“扫描”)的扫描过程。

然而,仅仅有当它当前已启用可被发现局部区域内的蓝牙设备会以发现请求作出响应。假设一个设备是可发现。它会通过共享一些信息,比如设备名称。类和其特有的MAC地址的发现请求作出响应。使用该信息,该设备运行发现随后能够选择发起对所发现的设备的连接。


一旦连接与用于第一次的远程设备制成。配对请求被自己主动呈现给用户。当一个设备被配对,关于该设备的基本信息(比如设备名称,类和MAC地址)被保存,而且能够使用蓝牙API来读取。

使用公知的MAC地址为远程设备中,连接能够用它在不论什么时间发起而不运行发现(如果设备在范围内)。


记得有被配对并连接之间的差。

进行配对意味着两个设备都知道彼此的存在。具有可以用于认证的共享链接密钥。而且可以建立与彼此的加密连接的。

要连接意味着设备眼下共享一个RFCOMM信道,而且可以彼此数据传输。眼下Android蓝牙API的要求,可以建立一个RFCOMM连接之前配对的设备。 (当你開始使用蓝牙API的一个加密的连接会自己主动进行配对。)
下面部分描写叙述了怎样找到已配对的设备,或使用设备发现发现新的设备。
注:Android系统的设备默认情况下不被发现。用户能够使设备可发如今有限的时间通过系统设置。或者应用程序能够要求用户能够发现能力。而无需离开应用程序。怎样启用可发如今以下讨论。
查询配对设备
运行设备发现之前,看到了它的价值查询组配对的设备,假设须要的设备是已知的。

要做到这一点。调用getBondedDevices()。

这将返回一组表示配对设备BluetoothDevices的。比如。您能够查询全部配对设备,然后显示每一个设备的username,使用ArrayAdapter:

Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices();
// If there are paired devices
if (pairedDevices.size() > 0) {
    // Loop through paired devices
    for (BluetoothDevice device : pairedDevices) {
        // Add the name and address to an array adapter to show in a ListView
        mArrayAdapter.add(device.getName() + "
" + device.getAddress());
    }
}
全部这一切从BluetoothDevice类对象所须要的。以发起连接的MAC地址。在这个样例中。它的储存做为所显示给用户一个ArrayAdapter的一部分。

MAC地址可在以后以发起连接被提取。

您能够了解很多其它有关创建大约连接设备部分的连接。
发现设备
要開始寻找设备,仅仅需调用startDiscovery()。这个过程是异步的。该方法将马上布尔值,指示是否发现已成功启动恢复。发现过程通常须要约12秒的查询扫描,随后每发现设备检索其蓝牙名称的页面扫描。
您的应用程序必须注冊为ACTION_FOUND意图一个BroadcastReceiver接收关于发现的每一个设备的信息。对于每一个设备,该系统将播出ACTION_FOUND意图。此意向进行额外的领域和EXTRA_DEVICE额外的类,分别包括蓝牙设备和BluetoothClass。比如,以下是当设备被发现。你怎样注冊处理广播:

// Create a BroadcastReceiver for ACTION_FOUND
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        // When discovery finds a device
        if (BluetoothDevice.ACTION_FOUND.equals(action)) {
            // Get the BluetoothDevice object from the Intent
            BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
            // Add the name and address to an array adapter to show in a ListView
            mArrayAdapter.add(device.getName() + "
" + device.getAddress());
        }
    }
};
// Register the BroadcastReceiver
IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
registerReceiver(mReceiver, filter); // Don't forget to unregister during onDestroy
全部这一切从BluetoothDevice类对象所须要的。以发起连接的MAC地址。在这个样例中,它的储存做为所显示给用户一个ArrayAdapter的一部分。 MAC地址可在以后以发起连接被提取。

您能够了解很多其它有关创建大约连接设备部分的连接。


注意:运行设备发现是蓝牙适配器一个沉重的程序,会消耗大量的资源。

一旦你找到了连接一个设备,能够肯定。你总是在尝试连接之前停止与发现cancelDiscovery()。此外。假设你已经持有一个设备的连接,然后运行发现能显著降低可用于连接带宽,所以你不应该在连接上运行搜索。


启用可发现


假设你想使本地设备可被其它设备,调用startActivityForResult(意向,INT)与ACTION_REQUEST_DISCOVERABLE行动意图。

这将发出一个请求,以使通过系统设置发现模式(无需停止应用程序)。默认情况下,该设备将成为可发现120秒。您能够通过加入EXTRA_DISCOVERABLE_DURATION意向额外的定义不同的持续时间。一个应用程序能够设置的最长持续时间为3600秒,值为0意味着设备总是发现。

低于0或高于3600的不论什么值会自己主动设置为120秒)。

比如,该片段设置期限为300:

Intent discoverableIntent = new
Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);
startActivity(discoverableIntent);
将显示一个对话框,要求用户权限,使设备可发现,如图2。假设用户回答“是”。则该设备将成为发现了指定的时间量。那么你的活动将接收呼叫到的onActivityResult())回调,结果代码等于该设备是可发现的持续时间。假设用户回答“否”。或者假设错误发生,结果代码将被RESULT_CANCELED。
注意:假设蓝牙尚未在设备上启用。则使设备可发现会自己主动启用蓝牙。


该装置会悄悄地留在发现模式指定的时间。假设您希望得到通知时,发现模式发生了变化,你可以注冊为ACTION_SCAN_MODE_CHANGED意图广播接收器。这将包括额外的领域EXTRA SCAN_MODE和EXTRA_PREVIOUS_SCAN_MODE。它告诉你新老扫描模式,分别为。对于每个可能的值有SCAN_MODE连接发现,SCAN_MODE_CONNECTABLE或SCAN_MODE_NONE。这表明该设备是可发现模式,而不是在发现模式。但仍然可以接收发现模式连接,或者没有,无法分别接收连接。
不须要启用设备可发现假设将发起到远程设备的连接。

启用可发现,当你想你的应用程序托管的server套接字将接受传入的连接不过必要的,由于远程设备必须可以发现设备才可以发起连接。

连接设备


为了创建两个设备上的应用程序之间的连接,必须同一时候实现server端和client的机制。由于一台设备必须打开一个server套接字。还有一个必须发起连接(使用server设备的MAC地址启动连接)。server和client被觉得是相互连接时。他们每一个人都有在同一个RFCOMM通道连接的BluetoothSocket。在这一点上,每一个设备都能够获取输入和输出流和传输数据能够開始,这是在大约管理一个连接的部分讨论。本节将介绍怎样启动两个设备之间的连接。




server设备和client设备的每一个获得以不同的方式所需的BluetoothSocket。

server将收到它时,传入的连接被接受。当它打开一个RFCOMM通道到server的client将收到它。




图3:蓝牙配对对话框。
一种实现方法是自己主动准备每一个设备作为server,让每一个人都有一台server套接字打开并侦听连接。

然后或者能够发起与其它的连接,并成为client。另外,一台设备能够明白的“主机”的连接,并打开需求的server插座和其它设备能够简单地启动连接。


注意:假设两个设备都没有进行过配对,那么Android框架会自己主动显示在连接过程中的配对请求通知或对话框给用户。作为尝试连接的设备所以当如图3所看到的,你的应用程序不须要关注设备是否被配对。你的RFCOMM连接尝试将堵塞,直到用户已成功配对。或者假设用户拒绝配对,假设配对失败或者超时就会失败。




连接作为server


当你想连接两个设备,一个必须由持开放BluetoothServerSocket充当server。server套接字的目的是监听传入的连接请求和当一个被接受时,提供一个连接的BluetoothSocket。当的BluetoothSocket从BluetoothServerSocket获得的,该BluetoothServerSocket能够(也应该)被丢弃,除非你想接受很多其它的连接。




关于UUID


通用唯一标识符(UUID)是用来唯一标识信息的字符串ID标准化的128位格式。一个UUID的一点是。它足够大。你能够选择不论什么随机的,也不会发生冲突。在这样的情况下,它是用来唯一标识应用程序的蓝牙服务。要获得UUID与你的应用程序中使用。则能够使用Web上的很多随机UUID生成器之中的一个,则初始化fromString(String)将UUID。
这里是主要的程序建立一个server套接字并接受连接:


通过调用listenUsingRfcommWithServiceRecord(字符串。UUID)获取BluetoothServerSocket。


该字符串是你的服务,系统会自己主动写入到一个新的服务发现协议在设备上(SDP)数据库条目的识别名称(名称是随意的。能够简单地将您的应用程序名称)。的UUID也包括在SDP条目和将用于与所述client设备的连接协定的基础。也就是说,当client试图与此设备连接,其将携带唯一标识与它要连接的服务一个UUID。这些的UUID必须以使连接被接受(在下一步骤)相匹配。


開始通过调用accept()方法监听连接请求。
这是一个堵塞调用。

当任一连接被接受或者已经发生异常它将返回。一个连接被接受,仅仅有当远程设备已派出匹配与此监听套接字server中注冊的一个UUID的连接请求。假设成功,accept()方法将返回一个连接的BluetoothSocket。
除非你想接受很多其它的连接。调用close()。
这将释放server插槽及其全部资源,但不会关闭一个已经被接受返回的连接的BluetoothSocket()。不像TCP / IP,RFCOMM仅仅同意每一个通道的一个连接的client的时间。因此,在大多数情况下,它是有道理的接受连接套接字后马上关闭()的调用BluetoothServerSocket。
的接受()调用不应该在主活动UI线程。由于它是一个堵塞调用。并防止与应用程序的不论什么其他交互来运行。它通常情理之中的事了BluetoothServerSocket或所有的BluetoothSocket工作,你的应用程序管理的一个新的线程。

要中止堵塞调用,如接受(),从还有一个线程调用close()在BluetoothServerSocket(或的BluetoothSocket)和堵塞调用将马上返回。

须要注意的是在BluetoothServerSocket或的BluetoothSocket的所有方法是线程安全的。







以下是接受传入连接的server组件的简化版本号:

private class AcceptThread extends Thread {
    private final BluetoothServerSocket mmServerSocket;
 
    public AcceptThread() {
        // Use a temporary object that is later assigned to mmServerSocket,
        // because mmServerSocket is final
        BluetoothServerSocket tmp = null;
        try {
            // MY_UUID is the app's UUID string, also used by the client code
            tmp = mBluetoothAdapter.listenUsingRfcommWithServiceRecord(NAME, MY_UUID);
        } catch (IOException e) { }
        mmServerSocket = tmp;
    }
 
    public void run() {
        BluetoothSocket socket = null;
        // Keep listening until exception occurs or a socket is returned
        while (true) {
            try {
                socket = mmServerSocket.accept();
            } catch (IOException e) {
                break;
            }
            // If a connection was accepted
            if (socket != null) {
                // Do work to manage the connection (in a separate thread)
                manageConnectedSocket(socket);
                mmServerSocket.close();
                break;
            }
        }
    }
 
    /** Will cancel the listening socket, and cause the thread to finish */
    public void cancel() {
        try {
            mmServerSocket.close();
        } catch (IOException e) { }
    }
}
在本实施例中。仅仅有一个传入的连接是须要的,所以仅仅要一个连接被接受以及的BluetoothSocket被获取时,应用程序发送所获取的BluetoothSocket到一个单独的线程,关闭BluetoothServerSocket并中断环路。
须要注意的是accept()返回的BluetoothSocket的时候,插座已连接,所以你不应该调用connect()(当你从client做的)。
管理器连接插座()是在将启动该线程用于传送数据,这是在大约管理一个连接部分中所讨论的应用的一个虚构的方法。
通常你应该尽快关闭BluetoothServerSocket为你做侦听传入连接。

在这个样例中,接近()被尽快的BluetoothSocket获取调用。您可能还须要提供你的线程公开的方法,能够在你须要停止监听server套接字上的事件关闭的BluetoothSocket私人。
连接作为client
为了与远程设备(设备保持一个开放的server套接字)的连接,您必须首先获取表示远程设备BluetoothDevice类的对象。 (获取一个BluetoothDevice类是覆盖在关于查找设备上面的部分。

)然后。您必须使用BluetoothDevice类收购的BluetoothSocket,并启动连接。


这里的基本步骤:
使用BluetoothDevice类。通过调用createRfcommSocketToServiceRecord(UUID)获得的BluetoothSocket。
这一个初始化的BluetoothSocket将连接到BluetoothDevice类。这里传递的UUID必须开业时其BluetoothServerSocket(带listenUsingRfcommWithServiceRecord(字符串。UUID))由server设备使用的UUID相匹配。

使用同样的UUID是一个简单的硬编码的UUID字符串到您的应用程序。然后从server端和client的代码都引用它的问题。


启动通过调用连接的连接()。


在此呼叫时。系统会以匹配的UUID远程设备上运行的SDP查找。假设查找成功与远程设备接受连接,它会共享连接过程中使用和connect()将返回RFCOMM通道。这样的方法是一个堵塞调用。

假设因不论什么原因,连接失败或者connect()方法超时(约12秒后)。那么它会抛出异常。


因为连接()是一个堵塞调用,这个连接过程应始终在一个线程运行从主线程的活动分开。
注意:您应始终确保设备未进行设备发现。当你调用connect()。假设发现是正在进行中,那么连接尝试将显著减缓,更可能失败。

这里是发起蓝牙连接一个线程的一个主要的样例:

private class ConnectThread extends Thread {
    private final BluetoothSocket mmSocket;
    private final BluetoothDevice mmDevice;
 
    public ConnectThread(BluetoothDevice device) {
        // Use a temporary object that is later assigned to mmSocket,
        // because mmSocket is final
        BluetoothSocket tmp = null;
        mmDevice = device;
 
        // Get a BluetoothSocket to connect with the given BluetoothDevice
        try {
            // MY_UUID is the app's UUID string, also used by the server code
            tmp = device.createRfcommSocketToServiceRecord(MY_UUID);
        } catch (IOException e) { }
        mmSocket = tmp;
    }
 
    public void run() {
        // Cancel discovery because it will slow down the connection
        mBluetoothAdapter.cancelDiscovery();
 
        try {
            // Connect the device through the socket. This will block
            // until it succeeds or throws an exception
            mmSocket.connect();
        } catch (IOException connectException) {
            // Unable to connect; close the socket and get out
            try {
                mmSocket.close();
            } catch (IOException closeException) { }
            return;
        }
 
        // Do work to manage the connection (in a separate thread)
        manageConnectedSocket(mmSocket);
    }
 
    /** Will cancel an in-progress connection, and close the socket */
    public void cancel() {
        try {
            mmSocket.close();
        } catch (IOException e) { }
    }
}
注意到cancelDiscovery()由连接之前被调用。

你应该总是连接之前做到这一点,它是安全的,而无需实际检查它是否正在执行或不调用(但假设你想查询。调用isDiscovering())。


manageConnectedSocket()是在将启动该线程用于传送数据,这是在大约管理一个连接部分中所讨论的应用的一个虚构的方法。


当你与你的BluetoothSocket完毕后。总是调用close()进行清理。

这样做将马上关​​闭连接套接字。并清理全部内部资源。


管理连接


当您成功连接的两个(或多个)设备,每个都会有一个连接的BluetoothSocket。

这是有趣的開始,由于你能够在设备之间共享数据。使用的BluetoothSocket,一般方法来传输随意数据是简单的:


获得通过套接字句柄传输的InputStream和OutputStream,通过的getInputStream()和的getOutputStream()。分别为。
具有读取读取和写入数据流(字节[])和写(字节[])。


而已。


有。当然,实现的细节要考虑。

首先,你应该使用一个专用的线程全部流读取和写入。

这是重要的。由于这两种读取(字节[])和写(字节[])方法堵塞调用。阅读(字节[])将堵塞,直到有东西从流中读取。写(字节[])通常不堵塞,但假设远程设备没有调用read(字节[])的速度不够快,并在中间缓冲区已满能够阻止流量控制。所以,你在线程主循环应专门用于从InputStream读取。

在线程一个单独的公共方法能够用于启动写入到输出流。





这里有一个怎样这可能外观的演示样例:

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;
 
        // Get the input and output streams, using temp objects because
        // member streams are final
        try {
            tmpIn = socket.getInputStream();
            tmpOut = socket.getOutputStream();
        } catch (IOException e) { }
 
        mmInStream = tmpIn;
        mmOutStream = tmpOut;
    }
 
    public void run() {
        byte[] buffer = new byte[1024];  // buffer store for the stream
        int bytes; // bytes returned from read()
 
        // Keep listening to the InputStream until an exception occurs
        while (true) {
            try {
                // Read from the InputStream
                bytes = mmInStream.read(buffer);
                // Send the obtained bytes to the UI activity
                mHandler.obtainMessage(MESSAGE_READ, bytes, -1, buffer)
                        .sendToTarget();
            } catch (IOException e) {
                break;
            }
        }
    }
 
    /* Call this from the main activity to send data to the remote device */
    public void write(byte[] bytes) {
        try {
            mmOutStream.write(bytes);
        } catch (IOException e) { }
    }
 
    /* Call this from the main activity to shutdown the connection */
    public void cancel() {
        try {
            mmSocket.close();
        } catch (IOException e) { }
    }
}
构造函数获取必要的数据流和运行一次,该线程将等待数据来通过InputStream的。当读取(字节[])与从流的字节返回时,数据是使用从父类中的成员处理程序发送到主活性。然后它返回,并等待从流很多其它的字节。




发送传出数据是从调用的主要活动线程的write()方法,并在字节传递给发送一样简单。然后,此方法简单地调用写(字节[])的数据发送到远程设备。




线程的取消()方法是重要的,这种连接能够在不论什么时候。通过关闭所述的BluetoothSocket被终止。当你使用蓝牙连接来完毕这应始终被调用。


对于使用蓝牙API的演示。请參见蓝牙聊天演示样例应用程序。


使用配置文件


在Android 3.0的開始,蓝牙API包含与蓝牙配置文件的工作的支持。蓝牙配置文件是设备间基于蓝牙的通信的无线接口规范。

一个样例是免提模式。对于手机连接到一个无线耳机,两个设备必须支持免提模式。




您能够实现接口BluetoothProfile编写自己的类来支持特定的Bluetooth配置文件。

Android的蓝牙API提供实现下面蓝牙规范:


耳机。耳机配置文件提供与手机使用蓝牙耳机的支持。

机器人提供BluetoothHeadset类,它是对经由进程间通信(IPC)控制所述蓝牙耳机服务的代理。这包含蓝牙耳机和免提(V1.5)型材。该BluetoothHeadset类包含AT命令的支持。有关此主题的很多其它讨论。请參阅供应商特定的AT命令
A2DP。

高级音频传输模式(A2DP)配置文件定义了怎样高品质的音频文件能够被串流从一个设备到还有一个通过蓝牙连接。机器人提供BluetoothA2dp类,它是通过IPC控制A2DP蓝牙服务的代理。
卫生设备。搭载Android 4.0(API级别14)引入了蓝牙医疗设备规范(HDP)的支持。这使您能够创建使用蓝牙与支持蓝牙的健康设备,如心脏速率监视器,血液米。温度计。衡器等通信的应用程序。对于支持的设备及其对应的设备数据专业化代码的列表。请參阅在www.bluetooth.org支持蓝牙编号分配。请注意。这些值也在ISO / IEEE 11073-20601 [7]规范作为MDC_DEV_SPEC_PROFILE_ *的命名代码附件中引用。对于HDP的很多其它讨论,请參见医疗设备规范。


以下是用于与信息的工作的基本步骤:


获取默认的适​​配器,如设置蓝牙描写叙述。
使用getProfileProxy()建立与配置文件关联的配置文件的代理对象的连接。

在以下的样例中,配置文件代理对象是BluetoothHeadset的一个实例。
设置一个BluetoothProfile.ServiceListener。

此侦听通知BluetoothProfile IPCclient时。他们已经连接或从服务断开。
在onServiceConnected(),得到一个处理配置文件代理对象。
一旦你的轮廓代理对象,你能够用它来监视连接的状态,并运行相关的该配置文件等操作。
比如,以下的代码片段展示了怎样连接到一个BluetoothHeadset代理对象,这样就能够控制耳机配置文件:

BluetoothHeadset mBluetoothHeadset;
 
// Get the default adapter
BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
 
// Establish connection to the proxy.
mBluetoothAdapter.getProfileProxy(context, mProfileListener, BluetoothProfile.HEADSET);
 
private BluetoothProfile.ServiceListener mProfileListener = new BluetoothProfile.ServiceListener() {
    public void onServiceConnected(int profile, BluetoothProfile proxy) {
        if (profile == BluetoothProfile.HEADSET) {
            mBluetoothHeadset = (BluetoothHeadset) proxy;
        }
    }
    public void onServiceDisconnected(int profile) {
        if (profile == BluetoothProfile.HEADSET) {
            mBluetoothHeadset = null;
        }
    }
};
 
// ... call functions on mBluetoothHeadset
 
// Close proxy connection after use.
mBluetoothAdapter.closeProfileProxy(mBluetoothHeadset);
供应商特定的AT命令


在Android 3.0的開始,应用能够注冊来接收的系统广播提前定义的供应商特定的AT通过耳机(如Plantronics的+ XEVENT命令)发送的命令。比如,应用程序能够接收指示一个连接的设备的电池电量广播并能够通知用户或依据须要採取其它行动。创建用于ACTION_VENDOR_SPECIFIC_HEADSET_EVENT意图处理厂商特定的AT的耳机命令的广播接收机。


医疗设备规范


搭载Android 4.0(API级别14)引入了蓝牙医疗设备规范(HDP)的支持。

这使您能够创建使用蓝牙与支持蓝牙的健康设备,如心脏速率监视器。血液米。温度计。而且可扩展到通信的应用程序。

蓝牙健康API包含类BluetoothHealth,BluetoothHealthCallback和BluetoothHealthAppConfiguration,这在基础知识介绍。


在使用蓝牙API健康。它有助于理解这些关键概念HDP:


概念说明
源HDP定义的角色。源是一种健康的设备。传输医疗数据(计重秤,血糖仪,温度计等)。智能设备如Android手机或平板电脑。
下沉HDP定义的角色。在HDP。水槽是接收医疗数据智能设备。

在一个Android应用程序HDP。水槽由BluetoothHealthAppConfiguration对象表示。
注冊是指注冊水槽特定保健设备。
连接是指打开保健设备与智能设备之间的信道。比如Android手机或平板电脑。


创建HDP应用


下面是參与创建一个Android应用程序HDP的基本步骤:


获取到BluetoothHealth代理对象的引用。
类似普通耳机和A2DP功能的设备。你必须调用getProfileProxy()与BluetoothProfile.ServiceListener和健康状况的类型,建立与轮廓的代理对象的连接。
创建BluetoothHealthCallback并注冊充当健康水槽应用程序配置(BluetoothHealthAppConfiguration)。


建立到卫生设备的连接。有些设备将启动连接。它是不须要进行此步骤的那些设备。
当成功地连接到一个医疗设备,读/写使用文件描写叙述符卫生设备。
所接收的数据须要使用它实现了IEEE 11073-XXXXX规格健康管理器来解释。
完毕后。关闭健康频道和注销应用程序。当有扩展活动的通道也关闭。
对于说明了这些步骤的完整代码演示样例。请參阅蓝牙HDP(健康设备配置文件)。


原文地址:https://www.cnblogs.com/blfbuaa/p/7341040.html