作者在这里介绍的这个实例是Google SDK中提供的一个蓝牙聊天程序,简单但信息量巨大,非常适合初学者学习蓝牙方面的知识。

在学习这个实例前请读者仔细阅读并理解Socket的工作原理和实现机制,作者的这篇博客中有详细的介绍:

http://blog.csdn.net/dlutbrucezhang/article/details/8577810


在 Android1.x 的时候,相关 API 非常不完善,还不能简单的使用 Bluetooth 开发,有一个开源项目可以帮助程序员使用、开发蓝牙,支持直接方法 bluetooth 协议栈。在 Android2 以后,框架提供了一些官方 API 来进行蓝牙的通信,但目前的程序也比较不完善。本文主要讨论 Android2 后的 Bluetooth 通信的 API 使用方法。

首先看聊天室的效果图:



蓝牙设备连接的过程如下图所示:


下面这张图展示的是蓝牙聊天的时序图:

接下来将贴出源码并对源码做出详细的解释说明:

BluetoothChat.java

例程的主 Activity 。 onCreate() 得到本地 BluetoothAdapter 设备,检查是否支持。 onStart() 中检查是否启用蓝牙,并请求启用,然后执行 setupChat() 。 setupChat() 中先对界面中的控件进行初始化增加点击监听器等,然创建 BluetoothChatService 对象,该对象在整个应用过程中存在,并执行蓝牙连接建立、消息发送接受等实际的行为。

import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.Window;
import android.view.View.OnClickListener;
import android.view.inputmethod.EditorInfo;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;/*** This is the main Activity that displays the current chat session.*/
public class BluetoothChat extends Activity {// Debuggingprivate static final String TAG = "BluetoothChat";private static final boolean D = true;// Message types sent from the BluetoothChatService Handlerpublic static final int MESSAGE_STATE_CHANGE = 1;public static final int MESSAGE_READ = 2;public static final int MESSAGE_WRITE = 3;public static final int MESSAGE_DEVICE_NAME = 4;public static final int MESSAGE_TOAST = 5;// Key names received from the BluetoothChatService Handlerpublic static final String DEVICE_NAME = "device_name";public static final String TOAST = "toast";// Intent request codesprivate static final int REQUEST_CONNECT_DEVICE = 1;private static final int REQUEST_ENABLE_BT = 2;// Layout Viewsprivate TextView mTitle;private ListView mConversationView;private EditText mOutEditText;private Button mSendButton;// Name of the connected deviceprivate String mConnectedDeviceName = null;// Array adapter for the conversation threadprivate ArrayAdapter<String> mConversationArrayAdapter;// String buffer for outgoing messagesprivate StringBuffer mOutStringBuffer;// Local Bluetooth adapterprivate BluetoothAdapter mBluetoothAdapter = null;// Member object for the chat servicesprivate BluetoothChatService mChatService = null;@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);if(D) Log.e(TAG, "+++ ON CREATE +++");// Set up the window layoutrequestWindowFeature(Window.FEATURE_CUSTOM_TITLE);setContentView(R.layout.main);getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE, R.layout.custom_title);// Set up the custom titlemTitle = (TextView) findViewById(R.id.title_left_text);mTitle.setText(R.string.app_name);mTitle = (TextView) findViewById(R.id.title_right_text);// Get local Bluetooth adaptermBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();// If the adapter is null, then Bluetooth is not supportedif (mBluetoothAdapter == null) {Toast.makeText(this, "Bluetooth is not available", Toast.LENGTH_LONG).show();finish();return;}}@Overridepublic void onStart() {super.onStart();if(D) Log.e(TAG, "++ ON START ++");// If BT is not on, request that it be enabled.// setupChat() will then be called during onActivityResultif (!mBluetoothAdapter.isEnabled()) {Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);startActivityForResult(enableIntent, REQUEST_ENABLE_BT);// Otherwise, setup the chat session} else {if (mChatService == null) setupChat();}}@Overridepublic synchronized void onResume() {super.onResume();if(D) Log.e(TAG, "+ ON RESUME +");// Performing this check in onResume() covers the case in which BT was// not enabled during onStart(), so we were paused to enable it...// onResume() will be called when ACTION_REQUEST_ENABLE activity returns.if (mChatService != null) {// Only if the state is STATE_NONE, do we know that we haven't started alreadyif (mChatService.getState() == BluetoothChatService.STATE_NONE) {// Start the Bluetooth chat servicesmChatService.start();}}}private void setupChat() {Log.d(TAG, "setupChat()");// Initialize the array adapter for the conversation threadmConversationArrayAdapter = new ArrayAdapter<String>(this, R.layout.message);mConversationView = (ListView) findViewById(R.id.in);mConversationView.setAdapter(mConversationArrayAdapter);// Initialize the compose field with a listener for the return keymOutEditText = (EditText) findViewById(R.id.edit_text_out);mOutEditText.setOnEditorActionListener(mWriteListener);// Initialize the send button with a listener that for click eventsmSendButton = (Button) findViewById(R.id.button_send);mSendButton.setOnClickListener(new OnClickListener() {public void onClick(View v) {// Send a message using content of the edit text widgetTextView view = (TextView) findViewById(R.id.edit_text_out);String message = view.getText().toString();sendMessage(message);}});// Initialize the BluetoothChatService to perform bluetooth connectionsmChatService = new BluetoothChatService(this, mHandler);// Initialize the buffer for outgoing messagesmOutStringBuffer = new StringBuffer("");}@Overridepublic synchronized void onPause() {super.onPause();if(D) Log.e(TAG, "- ON PAUSE -");}@Overridepublic void onStop() {super.onStop();if(D) Log.e(TAG, "-- ON STOP --");}@Overridepublic void onDestroy() {super.onDestroy();// Stop the Bluetooth chat servicesif (mChatService != null) mChatService.stop();if(D) Log.e(TAG, "--- ON DESTROY ---");}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);}}/*** Sends a message.* @param message  A string of text to send.*/private void sendMessage(String message) {// Check that we're actually connected before trying anythingif (mChatService.getState() != BluetoothChatService.STATE_CONNECTED) {Toast.makeText(this, R.string.not_connected, Toast.LENGTH_SHORT).show();return;}// Check that there's actually something to sendif (message.length() > 0) {// Get the message bytes and tell the BluetoothChatService to writebyte[] send = message.getBytes();mChatService.write(send);// Reset out string buffer to zero and clear the edit text fieldmOutStringBuffer.setLength(0);mOutEditText.setText(mOutStringBuffer);}}// The action listener for the EditText widget, to listen for the return keyprivate TextView.OnEditorActionListener mWriteListener =new TextView.OnEditorActionListener() {public boolean onEditorAction(TextView view, int actionId, KeyEvent event) {// If the action is a key-up event on the return key, send the messageif (actionId == EditorInfo.IME_NULL && event.getAction() == KeyEvent.ACTION_UP) {String message = view.getText().toString();sendMessage(message);}if(D) Log.i(TAG, "END onEditorAction");return true;}};// The Handler that gets information back from the BluetoothChatServiceprivate final Handler mHandler = new Handler() {@Overridepublic void handleMessage(Message msg) {switch (msg.what) {case MESSAGE_STATE_CHANGE:if(D) Log.i(TAG, "MESSAGE_STATE_CHANGE: " + msg.arg1);switch (msg.arg1) {case BluetoothChatService.STATE_CONNECTED:mTitle.setText(R.string.title_connected_to);mTitle.append(mConnectedDeviceName);mConversationArrayAdapter.clear();break;case BluetoothChatService.STATE_CONNECTING:mTitle.setText(R.string.title_connecting);break;case BluetoothChatService.STATE_LISTEN:case BluetoothChatService.STATE_NONE:mTitle.setText(R.string.title_not_connected);break;}break;case MESSAGE_WRITE:byte[] writeBuf = (byte[]) msg.obj;// construct a string from the bufferString writeMessage = new String(writeBuf);mConversationArrayAdapter.add("Me:  " + writeMessage);break;case MESSAGE_READ:byte[] readBuf = (byte[]) msg.obj;// construct a string from the valid bytes in the bufferString readMessage = new String(readBuf, 0, msg.arg1);mConversationArrayAdapter.add(mConnectedDeviceName+":  " + readMessage);break;case MESSAGE_DEVICE_NAME:// save the connected device's namemConnectedDeviceName = msg.getData().getString(DEVICE_NAME);Toast.makeText(getApplicationContext(), "Connected to "+ mConnectedDeviceName, Toast.LENGTH_SHORT).show();break;case MESSAGE_TOAST:Toast.makeText(getApplicationContext(), msg.getData().getString(TOAST),Toast.LENGTH_SHORT).show();break;}}};public void onActivityResult(int requestCode, int resultCode, Intent data) {if(D) Log.d(TAG, "onActivityResult " + resultCode);switch (requestCode) {case REQUEST_CONNECT_DEVICE:// When DeviceListActivity returns with a device to connectif (resultCode == Activity.RESULT_OK) {// Get the device MAC addressString address = data.getExtras().getString(DeviceListActivity.EXTRA_DEVICE_ADDRESS);// Get the BLuetoothDevice objectBluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);// Attempt to connect to the devicemChatService.connect(device);}break;case REQUEST_ENABLE_BT:// When the request to enable Bluetooth returnsif (resultCode == Activity.RESULT_OK) {// Bluetooth is now enabled, so set up a chat sessionsetupChat();} else {// User did not enable Bluetooth or an error occuredLog.d(TAG, "BT not enabled");Toast.makeText(this, R.string.bt_not_enabled_leaving, Toast.LENGTH_SHORT).show();finish();}}}@Overridepublic boolean onCreateOptionsMenu(Menu menu) {MenuInflater inflater = getMenuInflater();inflater.inflate(R.menu.option_menu, menu);return true;}@Overridepublic boolean onOptionsItemSelected(MenuItem item) {switch (item.getItemId()) {case R.id.scan:// Launch the DeviceListActivity to see devices and do scanIntent serverIntent = new Intent(this, DeviceListActivity.class);startActivityForResult(serverIntent, REQUEST_CONNECT_DEVICE);return true;case R.id.discoverable:// Ensure this device is discoverable by othersensureDiscoverable();return true;}return false;}}

BluetoothChatService.java

public synchronized void start() :

开启 mAcceptThread 线程,由于样例程序是仅 2 人的聊天过程,故之前先检测 mConnectThread 和 mConnectedThread 是否运行,运行则先退出这些线程。

public synchronized voidconnect(BluetoothDevice device) :

取消 CONNECTING 和 CONNECTED 状态下的相关线程,然后运行新的 mConnectThread 线程。

public synchronized voidconnected(BluetoothSocket socket, BluetoothDevice device) :

开启一个 ConnectedThread 来管理对应的当前连接。之前先取消任意现存的 mConnectThread 、 mConnectedThread 、 mAcceptThread 线程,然后开启新 mConnectedThread ,传入当前刚刚接受的socket 连接。最后通过 Handler 来通知 UI 连接 OK 。

public synchronized void stop() :

停止所有相关线程,设当前状态为 NONE 。

public void write(byte[] out) :

在 STATE_CONNECTED 状态下,调用 mConnectedThread 里的 write 方法,写入 byte 。

private void connectionFailed() :

连接失败的时候处理,通知 ui ,并设为 STATE_LISTEN 状态。

private void connectionLost() :

当连接失去的时候,设为 STATE_LISTEN 状态并通知 ui 。

内部类:

private class AcceptThread extendsThread :

创建监听线程,准备接受新连接。使用阻塞方式,调用 BluetoothServerSocket.accept() 。提供 cancel 方法关闭 socket 。

private class ConnectThread extendsThread :

这是定义的连接线程,专门用来对外发出连接对方蓝牙的请求和处理流程。构造函数里通过 BluetoothDevice.createRfcommSocketToServiceRecord() ,从待连接的 device 产生 BluetoothSocket. 然后在run 方法中 connect ,成功后调用 BluetoothChatSevice 的 connected() 方法。定义 cancel() 在关闭线程时能够关闭相关 socket 。

private class ConnectedThread extendsThread :

这个是双方蓝牙连接后一直运行的线程。构造函数中设置输入输出流。 Run 方法中使用阻塞模式的 InputStream.read() 循环读取输入流, 然后 post 到 UI 线程中更新聊天消息。也提供了 write() 将聊天消息写入输出流传输至对方,传输成功后回写入 UI 线程。最后 cancel() 关闭连接的 socket 。

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.UUID;import android.annotation.SuppressLint;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothServerSocket;
import android.bluetooth.BluetoothSocket;
import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;/*** This class does all the work for setting up and managing Bluetooth* connections with other devices. It has a thread that listens for* incoming connections, a thread for connecting with a device, and a* thread for performing data transmissions when connected.*/
@SuppressLint("NewApi")
public class BluetoothChatService {// Debuggingprivate static final String TAG = "BluetoothChatService";private static final boolean D = true;// Name for the SDP record when creating server socketprivate static final String NAME = "BluetoothChat";// Unique UUID for this applicationprivate static final UUID MY_UUID = UUID.fromString("fa87c0d0-afac-11de-8a39-0800200c9a66");// Member fieldsprivate final BluetoothAdapter mAdapter;private final Handler mHandler;private AcceptThread mAcceptThread;private ConnectThread mConnectThread;private ConnectedThread mConnectedThread;private int mState;// Constants that indicate the current connection statepublic static final int STATE_NONE = 0;       // we're doing nothingpublic static final int STATE_LISTEN = 1;     // now listening for incoming connectionspublic static final int STATE_CONNECTING = 2; // now initiating an outgoing connectionpublic static final int STATE_CONNECTED = 3;  // now connected to a remote device/*** Constructor. Prepares a new BluetoothChat session.* @param context  The UI Activity Context* @param handler  A Handler to send messages back to the UI Activity*/public BluetoothChatService(Context context, Handler handler) {mAdapter = BluetoothAdapter.getDefaultAdapter();mState = STATE_NONE;mHandler = handler;}/*** Set the current state of the chat connection* @param state  An integer defining the current connection state*/private synchronized void setState(int state) {if (D) Log.d(TAG, "setState() " + mState + " -> " + state);mState = state;// Give the new state to the Handler so the UI Activity can updatemHandler.obtainMessage(BluetoothChat.MESSAGE_STATE_CHANGE, state, -1).sendToTarget();}/*** Return the current connection state. */public synchronized int getState() {return mState;}/*** Start the chat service. Specifically start AcceptThread to begin a* session in listening (server) mode. Called by the Activity onResume() */public synchronized void start() {if (D) Log.d(TAG, "start");// Cancel any thread attempting to make a connectionif (mConnectThread != null) {mConnectThread.cancel(); mConnectThread = null;}// Cancel any thread currently running a connectionif (mConnectedThread != null) {mConnectedThread.cancel(); mConnectedThread = null;}// Start the thread to listen on a BluetoothServerSocketif (mAcceptThread == null) {mAcceptThread = new AcceptThread();mAcceptThread.start();}setState(STATE_LISTEN);}/*** Start the ConnectThread to initiate a connection to a remote device.* @param device  The BluetoothDevice to connect*/public synchronized void connect(BluetoothDevice device) {if (D) Log.d(TAG, "connect to: " + device);// Cancel any thread attempting to make a connectionif (mState == STATE_CONNECTING) {if (mConnectThread != null) {mConnectThread.cancel(); mConnectThread = null;}}// Cancel any thread currently running a connectionif (mConnectedThread != null) {mConnectedThread.cancel(); mConnectedThread = null;}// Start the thread to connect with the given devicemConnectThread = new ConnectThread(device);mConnectThread.start();setState(STATE_CONNECTING);}/*** Start the ConnectedThread to begin managing a Bluetooth connection* @param socket  The BluetoothSocket on which the connection was made* @param device  The BluetoothDevice that has been connected*/public synchronized void connected(BluetoothSocket socket, BluetoothDevice device) {if (D) Log.d(TAG, "connected");// Cancel the thread that completed the connectionif (mConnectThread != null) {mConnectThread.cancel(); mConnectThread = null;}// Cancel any thread currently running a connectionif (mConnectedThread != null) {mConnectedThread.cancel(); mConnectedThread = null;}// Cancel the accept thread because we only want to connect to one deviceif (mAcceptThread != null) {mAcceptThread.cancel(); mAcceptThread = null;}// Start the thread to manage the connection and perform transmissionsmConnectedThread = new ConnectedThread(socket);mConnectedThread.start();// Send the name of the connected device back to the UI ActivityMessage msg = mHandler.obtainMessage(BluetoothChat.MESSAGE_DEVICE_NAME);Bundle bundle = new Bundle();bundle.putString(BluetoothChat.DEVICE_NAME, device.getName());msg.setData(bundle);mHandler.sendMessage(msg);setState(STATE_CONNECTED);}/*** Stop all threads*/public synchronized void stop() {if (D) Log.d(TAG, "stop");if (mConnectThread != null) {mConnectThread.cancel(); mConnectThread = null;}if (mConnectedThread != null) {mConnectedThread.cancel(); mConnectedThread = null;}if (mAcceptThread != null) {mAcceptThread.cancel(); mAcceptThread = null;}setState(STATE_NONE);}/*** Write to the ConnectedThread in an unsynchronized manner* @param out The bytes to write* @see ConnectedThread#write(byte[])*/public void write(byte[] out) {// Create temporary objectConnectedThread r;// Synchronize a copy of the ConnectedThreadsynchronized (this) {if (mState != STATE_CONNECTED) return;r = mConnectedThread;}// Perform the write unsynchronizedr.write(out);}/*** Indicate that the connection attempt failed and notify the UI Activity.*/private void connectionFailed() {setState(STATE_LISTEN);// Send a failure message back to the ActivityMessage msg = mHandler.obtainMessage(BluetoothChat.MESSAGE_TOAST);Bundle bundle = new Bundle();bundle.putString(BluetoothChat.TOAST, "Unable to connect device");msg.setData(bundle);mHandler.sendMessage(msg);}/*** Indicate that the connection was lost and notify the UI Activity.*/private void connectionLost() {setState(STATE_LISTEN);// Send a failure message back to the ActivityMessage msg = mHandler.obtainMessage(BluetoothChat.MESSAGE_TOAST);Bundle bundle = new Bundle();bundle.putString(BluetoothChat.TOAST, "Device connection was lost");msg.setData(bundle);mHandler.sendMessage(msg);}/*** This thread runs while listening for incoming connections. It behaves* like a server-side client. It runs until a connection is accepted* (or until cancelled).*/@SuppressLint("NewApi")private class AcceptThread extends Thread {// The local server socketprivate final BluetoothServerSocket mmServerSocket;public AcceptThread() {BluetoothServerSocket tmp = null;// Create a new listening server sockettry {//开启监听tmp = mAdapter.listenUsingRfcommWithServiceRecord(NAME, MY_UUID);} catch (IOException e) {Log.e(TAG, "listen() failed", e);}mmServerSocket = tmp;}public void run() {if (D) Log.d(TAG, "BEGIN mAcceptThread" + this);setName("AcceptThread");BluetoothSocket socket = null;// Listen to the server socket if we're not connectedwhile (mState != STATE_CONNECTED) {try {// This is a blocking call and will only return on a// successful connection or an exceptionsocket = mmServerSocket.accept();} catch (IOException e) {Log.e(TAG, "accept() failed", e);break;}// If a connection was acceptedif (socket != null) {synchronized (BluetoothChatService.this) {switch (mState) {case STATE_LISTEN:case STATE_CONNECTING:// Situation normal. Start the connected thread.connected(socket, socket.getRemoteDevice());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");}public void cancel() {if (D) Log.d(TAG, "cancel " + this);try {mmServerSocket.close();} catch (IOException e) {Log.e(TAG, "close() of server failed", e);}}}/*** This thread runs while attempting to make an outgoing connection* with a device. It runs straight through; the connection either* succeeds or fails.*/private class ConnectThread extends Thread {private final BluetoothSocket mmSocket;private final BluetoothDevice mmDevice;public ConnectThread(BluetoothDevice device) {mmDevice = device;BluetoothSocket tmp = null;// Get a BluetoothSocket for a connection with the// given BluetoothDevicetry {tmp = device.createRfcommSocketToServiceRecord(MY_UUID);} catch (IOException e) {Log.e(TAG, "create() failed", e);}mmSocket = tmp;}public void run() {Log.i(TAG, "BEGIN mConnectThread");setName("ConnectThread");// Always cancel discovery because it will slow down a connectionmAdapter.cancelDiscovery();// Make a connection to the BluetoothSockettry {// This is a blocking call and will only return on a// successful connection or an exceptionmmSocket.connect();} catch (IOException e) {connectionFailed();// Close the sockettry {mmSocket.close();} catch (IOException e2) {Log.e(TAG, "unable to close() socket during connection failure", e2);}// Start the service over to restart listening modeBluetoothChatService.this.start();return;}// Reset the ConnectThread because we're donesynchronized (BluetoothChatService.this) {mConnectThread = null;}// Start the connected threadconnected(mmSocket, mmDevice);}public void cancel() {try {mmSocket.close();} catch (IOException e) {Log.e(TAG, "close() of connect socket failed", e);}}}/*** This thread runs during a connection with a remote device.* It handles all incoming and outgoing transmissions.*/private class ConnectedThread extends Thread {private final BluetoothSocket mmSocket;private final InputStream mmInStream;private final OutputStream mmOutStream;public ConnectedThread(BluetoothSocket socket) {Log.d(TAG, "create ConnectedThread");mmSocket = socket;InputStream tmpIn = null;OutputStream tmpOut = null;// Get the BluetoothSocket input and output streamstry {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 connectedwhile (true) {try {// Read from the InputStreambytes = mmInStream.read(buffer);// Send the obtained bytes to the UI ActivitymHandler.obtainMessage(BluetoothChat.MESSAGE_READ, bytes, -1, buffer).sendToTarget();} catch (IOException e) {Log.e(TAG, "disconnected", e);connectionLost();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 ActivitymHandler.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);}}}
}

DeviceListActivity.java

该类包含 UI 和操作的 Activity 类,作用是得到系统默认蓝牙设备的已配对设备列表,以及搜索出的未配对的新设备的列表。然后提供点击后发出连接设备请求的功能。

import java.util.Set;import android.annotation.SuppressLint;
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.Window;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.AdapterView.OnItemClickListener;/*** This Activity appears as a dialog. It lists any paired devices and* devices detected in the area after discovery. When a device is chosen* by the user, the MAC address of the device is sent back to the parent* Activity in the result Intent.*/
@SuppressLint("NewApi")
public class DeviceListActivity extends Activity {// Debuggingprivate static final String TAG = "DeviceListActivity";private static final boolean D = true;// Return Intent extrapublic static String EXTRA_DEVICE_ADDRESS = "device_address";// Member fieldsprivate BluetoothAdapter mBtAdapter;private ArrayAdapter<String> mPairedDevicesArrayAdapter;private ArrayAdapter<String> mNewDevicesArrayAdapter;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);// Setup the windowrequestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);setContentView(R.layout.device_list);// Set result CANCELED incase the user backs outsetResult(Activity.RESULT_CANCELED);// Initialize the button to perform device discoveryButton scanButton = (Button) findViewById(R.id.button_scan);scanButton.setOnClickListener(new OnClickListener() {public void onClick(View v) {doDiscovery();v.setVisibility(View.GONE);}});// Initialize array adapters. One for already paired devices and// one for newly discovered devicesmPairedDevicesArrayAdapter = new ArrayAdapter<String>(this, R.layout.device_name);mNewDevicesArrayAdapter = new ArrayAdapter<String>(this, R.layout.device_name);// Find and set up the ListView for paired devicesListView pairedListView = (ListView) findViewById(R.id.paired_devices);pairedListView.setAdapter(mPairedDevicesArrayAdapter);pairedListView.setOnItemClickListener(mDeviceClickListener);// Find and set up the ListView for newly discovered devicesListView newDevicesListView = (ListView) findViewById(R.id.new_devices);newDevicesListView.setAdapter(mNewDevicesArrayAdapter);newDevicesListView.setOnItemClickListener(mDeviceClickListener);// Register for broadcasts when a device is discoveredIntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);this.registerReceiver(mReceiver, filter);// Register for broadcasts when discovery has finishedfilter = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);this.registerReceiver(mReceiver, filter);// Get the local Bluetooth adaptermBtAdapter = BluetoothAdapter.getDefaultAdapter();// Get a set of currently paired devicesSet<BluetoothDevice> pairedDevices = mBtAdapter.getBondedDevices();// If there are paired devices, add each one to the ArrayAdapterif (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);}}@Overrideprotected void onDestroy() {super.onDestroy();// Make sure we're not doing discovery anymoreif (mBtAdapter != null) {mBtAdapter.cancelDiscovery();}// Unregister broadcast listenersthis.unregisterReceiver(mReceiver);}/*** Start device discover with the BluetoothAdapter*/private void doDiscovery() {if (D) Log.d(TAG, "doDiscovery()");// Indicate scanning in the titlesetProgressBarIndeterminateVisibility(true);setTitle(R.string.scanning);// Turn on sub-title for new devicesfindViewById(R.id.title_new_devices).setVisibility(View.VISIBLE);// If we're already discovering, stop itif (mBtAdapter.isDiscovering()) {mBtAdapter.cancelDiscovery();}// Request discover from BluetoothAdaptermBtAdapter.startDiscovery();}// The on-click listener for all devices in the ListViewsprivate 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 connectmBtAdapter.cancelDiscovery();// Get the device MAC address, which is the last 17 chars in the ViewString info = ((TextView) v).getText().toString();String address = info.substring(info.length() - 17);// Create the result Intent and include the MAC addressIntent intent = new Intent();intent.putExtra(EXTRA_DEVICE_ADDRESS, address);// Set result and finish this ActivitysetResult(Activity.RESULT_OK, intent);finish();}};// The BroadcastReceiver that listens for discovered devices and// changes the title when discovery is finishedprivate final BroadcastReceiver mReceiver = new BroadcastReceiver() {@Overridepublic void onReceive(Context context, Intent intent) {String action = intent.getAction();// When discovery finds a deviceif (BluetoothDevice.ACTION_FOUND.equals(action)) {// Get the BluetoothDevice object from the IntentBluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);// If it's already paired, skip it, because it's been listed alreadyif (device.getBondState() != BluetoothDevice.BOND_BONDED) {mNewDevicesArrayAdapter.add(device.getName() + "\n" + device.getAddress());}// When discovery is finished, change the Activity title} else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) {setProgressBarIndeterminateVisibility(false);setTitle(R.string.select_device);if (mNewDevicesArrayAdapter.getCount() == 0) {String noDevices = getResources().getText(R.string.none_found).toString();mNewDevicesArrayAdapter.add(noDevices);}}}};}

Android 蓝牙开发实例--蓝牙聊天程序的设计和实现相关推荐

  1. Android蓝牙开发 — 经典蓝牙BLE蓝牙

    一,前期基础知识储备 1)蓝牙是一种支持设备之间短距离通信的无线电技术(其他还包括红外,WIFI): 支持移动电话.笔记本电脑.无线耳机等设备之间进行信息的交换: Android支持的蓝牙协议栈:Bl ...

  2. Android蓝牙开发—经典蓝牙详细开发流程

    文章目录 开发流程 权限 核心API BlueToothAdapter getDefaultAdapter():获取BluetoothAdapter对象 判断设备是否支持蓝牙 判断蓝牙是否开启 get ...

  3. 【Android】蓝牙开发——经典蓝牙:配对与解除配对 实现配对或连接时不弹出配对框

    目录 一.配对方法 二.解除配对方法 三.配对/解除配对结果 四.justwork配对模式下,不弹出配对框 五.pincode配对模式下,不弹出配对框 六.小结 在之前的文章[Android]蓝牙开发 ...

  4. android pin码 经典蓝牙_Android蓝牙开发—经典蓝牙详细开发流程

    Android蓝牙开发-经典蓝牙详细开发流程 发布时间:2018-07-16 13:41, 浏览次数:637 , 标签: Android Android蓝牙开发前,首先要区分是经典蓝牙开发还是BLE( ...

  5. 蓝牙配对模式 java_【Android】蓝牙开发—— 经典蓝牙配对介绍(Java代码实现演示)附Demo源码...

    目录 前言 一.连接&配对方法介绍 二.演示:第一次连接蓝牙设备  &  直接与蓝牙设备建立配对 三.总结 四.补充 五.Demo案例源码地址: 前言 前面两篇文章[Android]蓝 ...

  6. 【Android】蓝牙开发—— 经典蓝牙配对介绍(Java代码实现演示)附Demo源码

    目录 前言 一.连接&配对方法介绍 二.演示:第一次连接蓝牙设备  &  直接与蓝牙设备建立配对 三.总结 四.补充 五.Demo案例源码地址: 前言 前面两篇文章[Android]蓝 ...

  7. 从零开始的nrf52832蓝牙开发(1)--蓝牙协议基础

    想要进行蓝牙开发,第一步肯定要对蓝牙协议有所了解.除了要对蓝牙的一些专业术语有所熟悉,还应该对蓝牙协议每层功能有一定认知. 概略图: 物理层(PHY): 物理层规定了蓝牙频段:2400MHz~2483 ...

  8. OpenCV android sdk配置OpenCV android NDK开发实例

    OpenCV android sdk配置OpenCV android NDK开发实例 [尊重原创,转载请注明出处]http://blog.csdn.net/guyuealian/article/det ...

  9. 开发android 输入法,Android输入法开发实例解析 Android开发技术

    Android输入法开发实例解析 Android开发技术 2013 年 4 月 13 日 这里我们建立表1为BiHua,同时构建两个字段,字段1为"input"来存放输入的,字段2 ...

最新文章

  1. GameDev.net日报 2010.11.12 要卖了
  2. Hadoop入门(二十)Mapreduce的最小值程序
  3. 鸭子在Java中打字? 好吧,不完全是
  4. docker mysql容器安装vim
  5. UML类图中箭头和线条的含义和用法
  6. ikm2022/IKM考试/ikm java
  7. Linux内核模块编程
  8. python在虚拟解释器环境中使用pip安装第三方库出现Requirement already satisfied错误
  9. RTF文件结构分析及其应用
  10. 无线传感器网络定位概念
  11. 一年级下册计算机教学计划,人教版一年级数学下册教学计划
  12. 微信小程序一行代码实现微信公众号页面代码复用
  13. java获取时间(今天,昨天,上周第一天,本周第一天,本周最后一天)
  14. linux查看摄像头参数+获取公网地址
  15. 利用VideoView简单实现视频播放 包括 横竖屏切换 声音 亮度 暂停
  16. 什么叫蓝筹股?什么叫蓝筹股票的特点
  17. 中国经济供给面的分析-中国视角下的宏观经济
  18. 有源rc电压放大器实验报告_【指月专栏】有源滤波柜的实物讲解,进来了解一下...
  19. FS210开发平台板载LED灯控制实验
  20. 数据备份 linux,linux下的数据备份

热门文章

  1. 使用 Linux 子系统部署 Node、Gradle 项目的构建工具
  2. Spring-Boot:5分钟掌握SpringBoot开发
  3. 开源MANO软件盘点
  4. 美图秀秀web开发文档
  5. OpenSSL生成自签名的sha256泛域名证书
  6. 由多线程引起的map取值为null的分析
  7. 091101 T IModel
  8. [转载]日历设计之重复事件规则设计
  9. 『中级篇』阿里云安装Docker企业版UCP和DTR(59)
  10. SpringBoot集成全局异常处理