2013.09.05——— android 蓝牙聊天室之官方例子
蓝牙开发的大致流程:
1、蓝牙权限
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.BLUETOOTH" />
2、认设备是否支持蓝牙
/**
* 确认设备是否支持蓝牙
* 如果getDefaultAdapter()返回null,则这个设备不支持蓝牙
*/
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
// If the adapter is null, then Bluetooth is not supported
//手机不支持蓝牙
if (mBluetoothAdapter == null) {
Toast.makeText(this, "Bluetooth is not available", Toast.LENGTH_LONG).show();
finish();
return;
}
3、确定蓝牙能够使用
/**
* 确定蓝牙能够使用。
* 通过isEnabled()来检查蓝牙当前是否可用。
* 如果这个方法返回false,则蓝牙不能够使用。这个时候 就请求蓝牙使用,通过intent来请求
* 在onActivityResult()里面判断
*/
if (!mBluetoothAdapter.isEnabled()) {
Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableIntent, REQUEST_ENABLE_BT);
// Otherwise, setup the chat session
}
会打开一个对话框中显示请求使用蓝牙权限。如果响应"Yes",这个进程完成(或失败)后你的应用将能够使用蓝牙,选择no,就结束应用
case REQUEST_ENABLE_BT:
// When the request to enable Bluetooth returns
if (resultCode == Activity.RESULT_OK) {
// Bluetooth is now enabled, so set up a chat session
//请求蓝牙成功,这个时候 蓝也可用
setupChat();
} else {
// User did not enable Bluetooth or an error occurred
//请求蓝牙失败,退出应用
Log.d(TAG, "BT not enabled");
Toast.makeText(this, R.string.bt_not_enabled_leaving, Toast.LENGTH_SHORT).show();
finish();
}
4、最为服务器端,你必须让其他设备能够看到你,才能跟你建立连接
//设置自己可以被其他设备搜索到
private void ensureDiscoverable() {
if(D) Log.d(TAG, "ensure discoverable");
if (mBluetoothAdapter.getScanMode() !=
BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
Intent discoverableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);
startActivity(discoverableIntent);
}
}
5、找已经匹配的设备
在搜索设备前,查询配对设备看需要的设备是否已经是已经存在是很值得的,可以调用getBondedDevices()来做到,该函数会返回一个描述配对设备BluetoothDevice的结果集
//查找已经匹配的设备
Set<BluetoothDevice> pairedDevices = mBtAdapter.getBondedDevices();
// If there are paired devices, add each one to the ArrayAdapter
if (pairedDevices.size() > 0) {
findViewById(R.id.title_paired_devices).setVisibility(View.VISIBLE);
for (BluetoothDevice device : pairedDevices) {
mPairedDevicesArrayAdapter.add(device.getName() + "\n" + device.getAddress());
}
} else {
String noDevices = getResources().getText(R.string.none_paired).toString();
mPairedDevicesArrayAdapter.add(noDevices);
}
6、扫描设备
/**
* Start device discover with the BluetoothAdapter
*/
private void doDiscovery() {
if (D) Log.d(TAG, "doDiscovery()");
// Indicate scanning in the title
setProgressBarIndeterminateVisibility(true);
setTitle(R.string.scanning);
// Turn on sub-title for new devices
findViewById(R.id.title_new_devices).setVisibility(View.VISIBLE);
// If we're already discovering, stop it
//如果正在搜索 就先停止
if (mBtAdapter.isDiscovering()) {
mBtAdapter.cancelDiscovery();
}
// Request discover from BluetoothAdapter
//搜索设备 用BroadcastReceiver接受BluetoothDevice.ACTION_FOUND
mBtAdapter.startDiscovery();
}
要开始搜索设备,只需简单的调用startDiscovery() 。该函数时异步的,调用后立即返回,返回值表示搜索是否成功开始。可以再BroadcastReceiver里面监听结果
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
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);
// If it's already paired, skip it, because it's been listed already
if (device.getBondState() != BluetoothDevice.BOND_BONDED) {
mNewDevicesArrayAdapter.add(device.getName() + "\n" + device.getAddress());
}
// When discovery is finished, change the Activity title
}
};
7、作为客户端连接
扫描出来的列表,单击任意一个item,得到这个设备的mac地址和name
// The on-click listener for all devices in the ListViews
private OnItemClickListener mDeviceClickListener = new OnItemClickListener() {
public void onItemClick(AdapterView<?> av, View v, int arg2, long arg3) {
// Cancel discovery because it's costly and we're about to connect
//停止搜索
mBtAdapter.cancelDiscovery();
// Get the device MAC address, which is the last 17 chars in the View
String info = ((TextView) v).getText().toString();
String address = info.substring(info.length() - 17);
// Create the result Intent and include the MAC address
Intent intent = new Intent();
intent.putExtra(EXTRA_DEVICE_ADDRESS, address);
// Set result and finish this Activity
setResult(Activity.RESULT_OK, intent);
finish();
}
};
根据mac地址 得到远端BluetoothDevice
BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
然后 根据device得到BluetoothSocket,并建立连接
private class ConnectThread extends Thread {
private final BluetoothSocket mmSocket;
private final BluetoothDevice mmDevice;
private String mSocketType;
public ConnectThread(BluetoothDevice device, boolean secure) {
mmDevice = device;
BluetoothSocket tmp = null;
mSocketType = secure ? "Secure" : "Insecure";
// Get a BluetoothSocket for a connection with the
// given BluetoothDevice
//来生成一个BluetoothSocket对象
//这个uuid必须服务器和客户端是同一个
try {
if (secure) {
tmp = device.createRfcommSocketToServiceRecord(
MY_UUID_SECURE);
} else {
tmp = device.createInsecureRfcommSocketToServiceRecord(
MY_UUID_INSECURE);
}
} catch (IOException e) {
Log.e(TAG, "Socket Type: " + mSocketType + "create() failed", e);
}
mmSocket = tmp;
}
public void run() {
Log.i(TAG, "BEGIN mConnectThread SocketType:" + mSocketType);
//设置当前线程名字
setName("ConnectThread" + mSocketType);
// Always cancel discovery because it will slow down a connection
//因为扫描设备 很浪费资源 停止扫描
mAdapter.cancelDiscovery();
// Make a connection to the BluetoothSocket
//用connect()完成连接
//系统会在远程设备上完成一个SDP查找来匹配UUID。
//如果查找成功并且远程设备接受连接,就共享RFCOMM信道,connect()会返回。
//这也是一个阻塞的调用,不管连接失败还是超时(12秒)都会抛出异常。
try {
// This is a blocking call and will only return on a
// successful connection or an exception
mmSocket.connect();
} catch (IOException e) {
// Close the socket
try {
mmSocket.close();
} catch (IOException e2) {
Log.e(TAG, "unable to close() " + mSocketType +
" socket during connection failure", e2);
}
connectionFailed();
return;
}
// Reset the ConnectThread because we're done
synchronized (BluetoothChatService.this) {
mConnectThread = null;
}
// Start the connected thread
//启动连接成功 可以通信的线程
connected(mmSocket, mmDevice, mSocketType);
}
public void cancel() {
try {
mmSocket.close();
} catch (IOException e) {
Log.e(TAG, "close() of connect " + mSocketType + " socket failed", e);
}
}
}
8、作为服务器端建立连接
private class AcceptThread extends Thread {
// The local server socket
private final BluetoothServerSocket mmServerSocket;
private String mSocketType;
public AcceptThread(boolean secure) {
BluetoothServerSocket tmp = null;
mSocketType = secure ? "Secure":"Insecure";
// Create a new listening server socket
//通过调用listenUsingRfcommWithServiceRecord(String, UUID)得到一个BluetoothServerSocket对象
try {
if (secure) {
tmp = mAdapter.listenUsingRfcommWithServiceRecord(NAME_SECURE,
MY_UUID_SECURE);
} else {
tmp = mAdapter.listenUsingInsecureRfcommWithServiceRecord(
NAME_INSECURE, MY_UUID_INSECURE);
}
} catch (IOException e) {
Log.e(TAG, "Socket Type: " + mSocketType + "listen() failed", e);
}
mmServerSocket = tmp;
}
public void run() {
if (D) Log.d(TAG, "Socket Type: " + mSocketType +
"BEGIN mAcceptThread" + this);
setName("AcceptThread" + mSocketType);
BluetoothSocket socket = null;
// Listen to the server socket if we're not connected
while (mState != STATE_CONNECTED) {
try {
// This is a blocking call and will only return on a
// successful connection or an exception
//通过调用accept()来侦听连接请求。
socket = mmServerSocket.accept();
} catch (IOException e) {
Log.e(TAG, "Socket Type: " + mSocketType + "accept() failed", e);
break;
}
// If a connection was accepted
if (socket != null) {
synchronized (BluetoothChatService.this) {
switch (mState) {
case STATE_LISTEN:
case STATE_CONNECTING:
// Situation normal. Start the connected thread.
connected(socket, socket.getRemoteDevice(),
mSocketType);
break;
case STATE_NONE:
case STATE_CONNECTED:
// Either not ready or already connected. Terminate new socket.
try {
socket.close();
} catch (IOException e) {
Log.e(TAG, "Could not close unwanted socket", e);
}
break;
}
}
}
}
if (D) Log.i(TAG, "END mAcceptThread, socket Type: " + mSocketType);
}
public void cancel() {
if (D) Log.d(TAG, "Socket Type" + mSocketType + "cancel " + this);
try {
mmServerSocket.close();
} catch (IOException e) {
Log.e(TAG, "Socket Type" + mSocketType + "close() of server failed", e);
}
}
}
9、与远端设备通信
//处理与远端的通信
private class ConnectedThread extends Thread {
private final BluetoothSocket mmSocket;
private final InputStream mmInStream;
private final OutputStream mmOutStream;
public ConnectedThread(BluetoothSocket socket, String socketType) {
Log.d(TAG, "create ConnectedThread: " + socketType);
mmSocket = socket;
InputStream tmpIn = null;
OutputStream tmpOut = null;
// Get the BluetoothSocket input and output streams
try {
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
} catch (IOException e) {
Log.e(TAG, "temp sockets not created", e);
}
mmInStream = tmpIn;
mmOutStream = tmpOut;
}
public void run() {
Log.i(TAG, "BEGIN mConnectedThread");
byte[] buffer = new byte[1024];
int bytes;
// Keep listening to the InputStream while connected
while (true) {
try {
// Read from the InputStream
bytes = mmInStream.read(buffer);
// Send the obtained bytes to the UI Activity
mHandler.obtainMessage(BluetoothChat.MESSAGE_READ, bytes, -1, buffer)
.sendToTarget();
} catch (IOException e) {
Log.e(TAG, "disconnected", e);
connectionLost();
// Start the service over to restart listening mode
BluetoothChatService.this.start();
break;
}
}
}
/**
* Write to the connected OutStream.
* @param buffer The bytes to write
*/
//发送信息给远端
public void write(byte[] buffer) {
try {
mmOutStream.write(buffer);
// Share the sent message back to the UI Activity
mHandler.obtainMessage(BluetoothChat.MESSAGE_WRITE, -1, -1, buffer)
.sendToTarget();
} catch (IOException e) {
Log.e(TAG, "Exception during write", e);
}
}
public void cancel() {
try {
mmSocket.close();
} catch (IOException e) {
Log.e(TAG, "close() of connect socket failed", e);
}
}
}
附件是官网的例子,稍微加了点注释
分享到:
相关推荐
基于因子分析的我国A股上市...争力评价——以医药企业为例_张澳.caj
发福利了,Aspose Total for NET 2013.09.10 最新破解,danny_su 大作,花了10个贡献分才下载的了!现免费提供大家:) This package contains the following .NET Components: - Aspose.BarCode for .NET v5.7.0.0 ...
微信小程序——新浪读书(截图+源码).zip 微信小程序——新浪读书(截图+源码).zip 微信小程序——新浪读书(截图+源码).zip 微信小程序——新浪读书(截图+源码).zip 微信小程序——新浪读书(截图+源码).zip ...
数据库大作业——学校人事信息管理系统.zip数据库大作业——学校人事信息管理系统.zip数据库大作业——学校人事信息管理系统.zip数据库大作业——学校人事信息管理系统.zip数据库大作业——学校人事信息管理系统.zip...
python项目——Word助手.zip python项目——Word助手.zip python项目——Word助手.zip python项目——Word助手.zip python项目——Word助手.zip python项目——Word助手.zip python项目——Word助手.zip python项目...
在Android平台上构建一个蓝牙聊天室是一项技术性强且实用的任务,涉及到Android系统中的蓝牙通信机制、UI设计以及数据传输等核心知识点。以下将详细介绍这些关键点。 首先,Android蓝牙通信是通过`BluetoothAdapter...
python项目——RCQ读者书库.zip python项目——RCQ读者书库.zip python项目——RCQ读者书库.zip python项目——RCQ读者书库.zip python项目——RCQ读者书库.zip python项目——RCQ读者书库.zip python项目——RCQ...
本文将详细解析“安卓应用开发案例——蓝牙聊天工具代码BluetoothChat.rar”这个压缩包中的知识点,帮助你了解如何在Android平台上构建一个功能完备的蓝牙聊天应用程序。 首先,我们关注的是“蓝牙聊天”这一核心...
EDA_BOMHelper V2013.10.10原版软件,可以用和谐补丁。支持32位系统。
Android BLE蓝牙例子(包括android版Lightblue)实例源码: 源码里面有Bluetooth4_3/BLEDemo/Android_Lightblue.apk三个.前两个是BLE的demo。BLEDemo这个功能较Bluetooth4_3多一些,有兴趣的可以都看下。Android_...
Geomagic.Studio.2012软件,由于太大,分成八个压缩包以及一个其他文件包。 此文件为part5
【Java练手小项目——多线程聊天室】 在Java编程世界中,多线程是不可或缺的一部分,尤其在开发实时性、交互性强的应用时,如我们的主题“多线程聊天室”。这个实战项目旨在帮助开发者深入理解Java多线程的概念,并...
Android support.v7包
实用源码——Android屏幕锁源码.zip 实用源码——Android屏幕锁源码.zip 实用源码——Android屏幕锁源码.zip 实用源码——Android屏幕锁源码.zip 实用源码——Android屏幕锁源码.zip
Android中文翻译组——Android中文API合集(4).chm
matlab课程设计——调幅广播系统的仿真设计 完整版.docxmatlab课程设计——调幅广播系统的仿真设计 完整版.docxmatlab课程设计——调幅广播系统的仿真设计 完整版.docxmatlab课程设计——调幅广播系统的仿真设计 ...
有偏技术进步、要素配置扭曲...发展——基于技术一致性视角_蔺鹏 (1).caj
在Android系统中,APK是应用程序的安装包,它包含了所有必要的代码、资源和配置文件。为了让用户能够从非Google Play商店来源安装APK,并确保其安全性和完整性,开发者需要对APK进行签名。签名过程涉及到一系列的...
基于FLO-2D的泥石流灾...评价——以麦多沟泥石流为例_李宝幸.caj