您的位置:首页 > 产品设计 > UI/UE

android bluetooth开发基础-6连接设备

2013-10-29 15:21 471 查看
为了在两台设备上创建一个连接,你必须在软件上实现服务器端和客户端的机制,因为一个设备必须必须打开一个server socket,而另一个必须初始化这个连接(使用服务器端设备的MAC地址进行初始化)。

当服务器端和客户端在同一个RFCOMM信道上都有一个BluetoothSocket时,就可以认为它们之间建立了一个连接。在这个时刻,每个设备能获得一个输出流和一个输入流,也能够开始数据传输。本节介绍如何在两个设备之间初始化一个连接。

服务器端和客户端获得BluetoothSocket的方法是不同的,服务器端是当一个进入的连接被接受时才产生一个BluetoothSocket,客户端是在打开一个到服务器端的RFCOMM信道时获得BluetoothSocket的。



Figure 3: The Bluetooth pairing dialog.

一种实现技术是,每一个设备都自动作为一个服务器,所以每个设备都有一个server socket并监听连接。然后每个设备都能作为客户端建立一个到另一台设备的连接。另外一种代替方法是,一个设备按需打开一个server socket,另外一个设备仅初始化一个到这个设备的连接。

Note: 如果两个设备在建立连接之前并没有配对,那么在建立连接的过程中,Android框架将自动显示一个配对请求的notification或者一个对话框,如Figure 3所示。所以,在尝试连接设备时,你的应用程序无需确保设备之间已经进行了配对。你的RFCOMM连接将会在用户确认配对之后继续进行,或者用户拒绝或者超时之后失败。


作为一个服务器进行连接

当你想要连接两个设备时,其中一个必须保持一个打开的BluetoothServerSocket,作为服务器。服务器socket将监听进入的连接请求,一旦连接被接受,将产生一个BluetoothSocket。

About UUID

一个Universally Unique Identifier(UUID)是一个字符串ID的标准化128位格式,将被用于唯一标识信息。你可以使用web上的任何一款UUID产生器为你的程序获取一个UUID,然后使用fromString(String)初始化一个UUID。你可以用UUID来标识你的蓝牙服务。

这儿是展示设置一个server socket并接受一个连接的基础过程:

调用
listenUsingRfcommWithServiceRecord(String,
UUID)获得一个
BluetoothServerSocket

字符串参数是你的服务的标识名,系统将自动将这个标识名写到设备上一个新的Service Discovery Protocol(SDP)数据库条目中(这个标识名可以简单地作为你的程序的名字,也就是说可以把你的程序的名字作为命名)。UUID也会被包含在这个新的SDP条目中,并作为与客户端设备建立连接的基础。 That is, when the client attempts to connect with this device, it will carry a UUID that uniquely identifies
the service with which it wants to connect. These UUIDs must match in order for the connection to be accepted (in the next step).

调用[code]accept()开始监听连接请求

这是一个阻塞调用。当一个连接被接受或者发生异常时将返回。一个连接,仅当一个远程设备发出的请求包含UUID匹配正在监听的server socket所注册的UUID时被接受。成功的时候,accept()将返回一个连接的BluetoothSocket。

除非你要接受另外一个连接,否则调用close,关闭server socket。
这将释放server socket和它占用的所有资源,但不要用来关闭accept返回的已连接的BluetoothSocket。不像TCP/IP,RFCOMM仅允许一个信道在某一时刻有一个连接的客户端。所以,创建了一个连接的socket之后立即调用close()来关闭BluetoothServerSocket。

accept()方法不应该在主Activity UI线程中执行,因为它是一个阻塞调用,如果在主Activity UI线程中条也能够将会阻止与用户的交互。一般使用BluetoothServerSocket或者BluetoothSocket进行相关工作时都是在一个新的线程中。为了避免调用诸如accept()这样的阻塞调用,针对来自其他线程的BluetoothServerSocket或者BluetoothSocket调用close()将会使阻塞调用立即返回。注意,针对BluetoothServerSocket或者BluetoothSocket调用的方法都是线程安全的,也就是说可以在多个线程中使用。


示例

[java] view
plaincopy

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 = mAdapter.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) { }

}

}

manageConnectedSocket()
这个方法能初始化用于传输数据的线程。

感觉这些英语基本上都能看懂,就不翻译了...


Connecting as a client

In order to initiate a connection with a remote device (a device holding an open server socket), you must first obtain a
BluetoothDevice
object
that represents the remote device. (Getting a
BluetoothDevice
is covered in the above
section about Finding Devices.) You must then use the
BluetoothDevice
to
acquire a
BluetoothSocket
and initiate the connection.

Here's the basic procedure:

Using the
BluetoothDevice
, get a
BluetoothSocket
by
calling
createRfcommSocketToServiceRecord(UUID)
.
This initializes a
BluetoothSocket
that will connect to the
BluetoothDevice
.
The UUID passed here must match the UUID used by the server device when it opened its
BluetoothServerSocket
(with
listenUsingRfcommWithServiceRecord(String,
UUID)
). Using the same UUID is simply a matter of hard-coding the UUID string into your application and then referencing it from both the server and client code.

Initiate the connection by calling
connect()
.
Upon this call, the system will perform an SDP lookup on the remote device in order to match the UUID. If the lookup is successful and the remote device accepts the connection, it will share the RFCOMM channel to use during the connection and
connect()
will
return. This method is a blocking call. If, for any reason, the connection fails or the
connect()
method
times out (after about 12 seconds), then it will throw an exception.

Because
connect()
is a blocking call, this connection procedure should
always be performed in a thread separate from the main Activity thread.

Note: You should always ensure that the device is not performing device discovery when you call
connect()
.
If discovery is in progress, then the connection attempt will be significantly slowed and is more likely to fail.


Example

Here is a basic example of a thread that initiates a Bluetooth connection:
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
mAdapter.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) { }
}
}


Notice that
cancelDiscovery()
is called before the connection
is made. You should always do this before connecting and it is safe to call without actually checking whether it is running or not (but if you do want to check, call
isDiscovering()
).

manageConnectedSocket()
is a fictional method in the application that will initiate the thread for transferring data, which is discussed in the section about Managing
a Connection.

When you're done with your
BluetoothSocket
, always call
close()
to
clean up. Doing so will immediately close the connected socket and clean up all internal resources.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: