在开始学Android开发的时候,由于其他的需要,本着学习的心态,再网上找了一个资源,做了一个手机蓝牙串口的调试助手。
蓝牙通信技术可以在短距离传输中以无线电的方式传递数据,借助蓝牙通信技术来创造便利性,智能性和可控性[8]。实现Android应用程序与蓝牙设备连接,类似TCP连接,构建Android蓝牙通信连接两个关键类是BluetoothSocket和BluetoothServerSocket[9]。
在Android蓝牙通信连接的开发中,实现基本功能蓝牙通信软件,则需要在软件实现服务端和客户端两种机制[10]。这种通信构建需要在服务端程序根据UUID(通用唯一识别码)调用listenUsingRfcommWithServiceRecord(String,UUID)获得BluetoothServerSocket对象,在子线程调用accept()方法开启监听线程。在客户端也根据UUID(通用唯一识别码)调用createRfcommSocketToServiceRecord(UUID)获取BluetoothSocket,在子线程调用connect()方法发起请求连接。
构建蓝牙通信连接后,不管是服务器还是客户端机制,彼此都会连接好的BluetoothSocket对象,获取对应的输入字节流(inputstream)和输出字节流(outputstream),可调用它们的read(byte[])和write(byte[])方法来分别实现对数据流的读和写,实现蓝牙数据通信功能。
接下来大体过一下代码,代码 基本都有注释,基本应该都能看的懂,由于时间原因就不一一介绍了:
构建蓝牙的基本服务类BluetoothChatService.class
/**
* 这个类做了所有设置和管理与其它蓝牙设备连接的工作。
* 它有一个线程监听传入连接,一个线程与设备进行连接,还有一个线程负责连接后的数据传输。
*
*/
public class BluetoothChatService {
// Debugging
private static final String TAG = "BluetoothChatService";
private static final boolean D = true;
// 创建服务器套接字时SDP记录的名称
private static final String NAME = "BluetoothChat";
// 该应用的唯一UUID
private static final UUID MY_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
// 成员变量
private final BluetoothAdapter mAdapter;
private final Handler mHandler;
private AcceptThread mAcceptThread;
private ConnectThread mConnectThread;
private ConnectedThread mConnectedThread;
private int mState;
// 指示当前连接状态的常量
public static final int STATE_NONE = 0; // we're doing nothing
public static final int STATE_LISTEN = 1; // 现在正在侦听传入连接
public static final int STATE_CONNECTING = 2; // 现在启动传出连接
public static final int STATE_CONNECTED = 3; // 现在连接到远程设备
//蓝牙接收延迟时间
private int delay_time;
public void setDelay_time(int delay_time) {
this.delay_time = delay_time;
}
/**
* 构造函数。 准备新的BluetoothChat会话。
* @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;
delay_time=100;
}
/**
* 设置聊天连接的当前状态
* @param 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 update
mHandler.obtainMessage(BluetoothChat.MESSAGE_STATE_CHANGE, state, -1).sendToTarget();
}
/**
* 返回当前连接状态。 */
public synchronized int getState() {
return mState;
}
/**
* 启动聊天服务。 特别地启动AcceptThread以在侦听(服务器)模式下开始会话。
* 由Activity onResume()调用 */
public synchronized void start() {
if (D) Log.d(TAG, "start");
// 取消尝试建立连接的任何线程
if (mConnectThread != null) {mConnectThread.cancel(); mConnectThread = null;}
// 取消当前运行连接的任何线程
if (mConnectedThread != null) {mConnectedThread.cancel(); mConnectedThread = null;}
// 启动线程以监听BluetoothServerSocket
if (mAcceptThread == null) {
mAcceptThread = new AcceptThread();
mAcceptThread.start();
}
setState(STATE_LISTEN);
}
/**
* 启动ConnectThread以启动与远程设备的连接。
* @param device 要连接的BluetoothDevice
*/
public synchronized void connect(BluetoothDevice device) {
if (D) Log.d(TAG, "connect to: " + device);
// 取消尝试建立连接的任何线程
if (mState == STATE_CONNECTING) {
if (mConnectThread != null) {mConnectThread.cancel(); mConnectThread = null;}
}
// 取消当前运行连接的任何线程
if (mConnectedThread != null) {mConnectedThread.cancel(); mConnectedThread = null;}
// 启动线程以与给定设备连接
mConnectThread = new ConnectThread(device);
mConnectThread.start();
setState(STATE_CONNECTING);
}
/**
* 启动ConnectedThread以开始管理蓝牙连接
* @param socket 在其上进行连接的BluetoothSocket
* @param device 已连接的BluetoothDevice
*/
public synchronized void connected(BluetoothSocket socket, BluetoothDevice device) {
if (D) Log.d(TAG, "connected");
// 取消完成连接的线程
if (mConnectThread != null) {mConnectThread.cancel(); mConnectThread = null;}
// 取消当前运行连接的任何线程
if (mConnectedThread != null) {mConnectedThread.cancel(); mConnectedThread = null;}
// 取消接受线程,因为我们只想连接到一个设备
if (mAcceptThread != null) {mAcceptThread.cancel(); mAcceptThread = null;}
// 启动线程以管理连接并执行传输
mConnectedThread = new ConnectedThread(socket);
mConnectedThread.start();
//将连接的设备的名称发送回UI活动
Message 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);
}
/**
* 以线程锁(不同步)方式写入ConnectedThread
* @param out 要写入的字节
* @see ConnectedThread#write(byte[])
*/
public void write(byte[] out) {
//创建临时对象
ConnectedThread r;
// 同步ConnectedThread的副本
synchronized (this) {
if (mState != STATE_CONNECTED) return;
r = mConnectedThread;
}
//执行写入不同步
r.write(out);
}
/**
* 指示连接尝试失败并通知UI活动.
*/
private void connectionFailed() {
setState(STATE_LISTEN);
// 将失败消息发送回活动
Message msg = mHandler.obtainMessage(BluetoothChat.MESSAGE_TOAST);
Bundle bundle = new Bundle();
bundle.putString(BluetoothChat.TOAST, "无法连接设备");
msg.setData(bundle);
mHandler.sendMessage(msg);
}
/**
* 指示连接已丢失并通知UI活动
*/
private void connectionLost() {
setState(STATE_LISTEN);
// 将失败消息发送回活动
Message msg = mHandler.obtainMessage(BluetoothChat.MESSAGE_TOAST);
Bundle bundle = new Bundle();
bundle.putString(BluetoothChat.TOAST, "丢失设备连接");
msg.setData(bundle);
mHandler.sendMessage(msg);
}
/**
* 此线程在侦听传入连接时运行。 它的行为像一个服务器端。
* 它运行直到接受连接
* (或直到取消).
*/
private class AcceptThread extends Thread {
// 本地服务器套接字
private final BluetoothServerSocket mmServerSocket;
public AcceptThread() {
BluetoothServerSocket tmp = null;
// 创建一个新的侦听服务器套接字
try {
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;
// 如果我们没有连接,请监听服务器插座
while (mState != STATE_CONNECTED) {
try {
// 这是一个阻塞调用,只会在成功的连接或异常返回
socket = mmServerSocket.accept();
} catch (IOException e) {
Log.e(TAG, "accept() failed", e);
break;
}
// 如果连接被接受
if (socket != null) {
synchronized (BluetoothChatService.this) {
switch (mState) {
case STATE_LISTEN:
case STATE_CONNECTING:
// 状况正常。 启动连接的线程。
connected(socket, socket.getRemoteDevice());
break;
case STATE_NONE:
case STATE_CONNECTED:
//未准备就绪或已连接。 终止新套接字。
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);
}
}
}
/**
* 尝试与设备建立传出连接时,此线程运行。类似于一个客户端
* 它直通; 连接
* 成功或失败。
*/
private class ConnectThread extends Thread {
private final BluetoothSocket mmSocket;
private final BluetoothDevice mmDevice;
public ConnectThread(BluetoothDevice device) {
mmDevice = device;
BluetoothSocket tmp = null;
// 获取与给定的蓝牙设备的连接的BluetoothSocket
try {
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");
// 始终取消发现,因为它会减慢连接速度
mAdapter.cancelDiscovery();
//连接到BluetoothSocket
try {
// 这是一个阻塞调用,只会在成功的连接或异常返回
mmSocket.connect();
} catch (IOException e) {
connectionFailed();
// Close the socket
try {
mmSocket.close();
} catch (IOException e2) {
Log.e(TAG, "unable to close() socket during connection failure", e2);
}
// 启动服务以重新启动侦听模式
BluetoothChatService.this.start();
return;
}
// 重置ConnectThread,因为我们完成了
synchronized (BluetoothChatService.this) {
mConnectThread = null;
}
// 启动连接的线程
connected(mmSocket, mmDevice);
}
public void cancel() {
try {
mmSocket.close();
} catch (IOException e) {
Log.e(TAG, "close() of connect socket failed", e);
}
}
}
/**
* 此线程在与远程设备的连接期间运行。
* 它处理所有传入和传出传输。
*/
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;
// 获取BluetoothSocket输入和输出流
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;
while (true) {
try {
while(mmInStream.available()==0){
}
try {
Thread.sleep(delay_time); //当有数据流入时,线程休眠一段时间,默认100ms
} catch (InterruptedException e) {
e.printStackTrace();
}
bytes = mmInStream.read(buffer); //从字节流中读取数据填充到字节数组,返回读取数据的长度
mHandler.obtainMessage(BluetoothChat.MESSAGE_READ, bytes, -1, buffer)
.sendToTarget(); //将消息传回主界面
} catch (IOException e) {
Log.e(TAG, "disconnected", e);
connectionLost();
break;
}
}
}
/**
* 写入连接的OutStream。
* @param buffer The bytes to write
*/
public void write(byte[] buffer) {
try {
mmOutStream.write(buffer);
//将发送的消息共享回UI活动
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);
}
}
}
}
主要显示视图UI类 BluetoothChat.class类
/**
* 显示通信信息的主Activity。
*/
public class BluetoothChat extends Activity {
// Debugging
private static final String TAG = "BluetoothChat";
private static final boolean D = true;
//返回页面标志
private boolean exit =false;
// 来自BluetoothChatService Handler的消息类型
public 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;
// 来自BluetoothChatService Handler的关键名
public static final String DEVICE_NAME = "device_name";
public static final String TOAST = "toast";
// Intent请求代码
private static final int REQUEST_CONNECT_DEVICE = 1;
private static final int REQUEST_ENABLE_BT = 2;
// 布局视图
private TextView mTitle;
private TextView mConversationView;
private TextView outcount;
private TextView incount;
private TextView view;
// 声明复选按钮
private CheckBox in16;
private CheckBox autosend;
private CheckBox out16;
// 声明button按钮
private Button mSendButton;
private Button search;
private Button disc;
// 用来保存存储的文件名
public String filename = "";
// 保存用数据缓存
private String fmsg = "";
// 计数用
private int countin = 0;
private int countout = 0;
// 已连接设备的名称
private String mConnectedDeviceName = null;
// 输出流缓冲区
private StringBuffer mOutStringBuffer;
// 本地蓝牙适配器
private BluetoothAdapter mBluetoothAdapter = null;
// 用于通信的服务
private BluetoothChatService mChatService = null;
// CheckBox用
private boolean inhex = true;
private boolean outhex = true;
private boolean auto = false;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (D)
Log.e(TAG, "+++ ON CREATE +++");
// 设置窗口布局
requestWindowFeature(Window.FEATURE_CUSTOM_TITLE);
setContentView(R.layout.activity_bluetooth_chat_layout);
getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE,
R.layout.custom_title);
//布局控件初始化函数,注册相关监听器
init();
// 获取本地蓝牙适配器
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
// 如果没有蓝牙适配器,则不支持
if (mBluetoothAdapter == null) {
Toast.makeText(this, "蓝牙不可用", Toast.LENGTH_LONG).show();
finish();
return;
}
search.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
search();
}
});
disc.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(BluetoothChat.this, "该设备已设置为可在300秒内发现,且可连接",
Toast.LENGTH_SHORT).show();
ensureDiscoverable();
}
});
}
public void search(){
Intent serverIntent = new Intent(BluetoothChat.this,
device.class);
startActivityForResult(serverIntent, REQUEST_CONNECT_DEVICE);
}
private void init(){
// 通过findViewById获得CheckBox对象
in16 = (CheckBox) findViewById(R.id.in16);
autosend = (CheckBox) findViewById(R.id.autosend);
out16 = (CheckBox) findViewById(R.id.out16);
// 注册事件监听器
in16.setOnCheckedChangeListener(listener);
autosend.setOnCheckedChangeListener(listener);
out16.setOnCheckedChangeListener(listener);
// 获得button的对象
search = (Button) findViewById(R.id.search);
disc = (Button) findViewById(R.id.discoverable1);
mSendButton = (Button) findViewById(R.id.button_send);
//获取选择控件的值
// 设置custom title
mTitle = (TextView) findViewById(R.id.title_left_text);
mTitle.setText(R.string.activity_name);
mTitle = (TextView) findViewById(R.id.title_right_text);
view = (TextView) findViewById(R.id.edit_text_out);
}
// 响应事件监听
private OnCheckedChangeListener listener = new OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView,
boolean isChecked) {
// in16被选中
if (buttonView.getId() == R.id.in16) {
if (isChecked) {
Toast.makeText(BluetoothChat.this, "16进制显示",
Toast.LENGTH_SHORT).show();
inhex = true;
} else
inhex = false;
}
//out16选中
if (buttonView.getId() == R.id.out16) {
if (isChecked) {
Toast.makeText(BluetoothChat.this, "16进制发送",
Toast.LENGTH_SHORT).show();
outhex = true;
} else
outhex = false;
}
// 自动发送被选中
if (buttonView.getId() == R.id.autosend) {
if (isChecked) {
Toast.makeText(BluetoothChat.this, "自动发送",
Toast.LENGTH_SHORT).show();
auto = true;
} else
auto = false;
}
}
};
@Override
public void onStart() {
super.onStart();
if (D)
Log.e(TAG, "++ ON START ++");
//如果BT未打开,请求启用。
// 然后在onActivityResult期间调用setupChat()
if (!mBluetoothAdapter.isEnabled())
{
Intent enableIntent = new Intent(
BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableIntent, REQUEST_ENABLE_BT);
// 否则,设置聊天会话
}
else
{
if (mChatService == null)
setupChat();
else {
try {
mChatService.wait(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
//300秒内搜索
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);
}
}
//自动发送
private Runnable runnable = new Runnable() {
@Override
public void run() {
String message = view.getText().toString();
sendMessage(message);
// 初始化输出流缓冲区
mOutStringBuffer = new StringBuffer("");
}
};
//初始化
private void setupChat() {
Log.d(TAG, "setupChat()");
mConversationView = (TextView) findViewById(R.id.in);
mConversationView.setMovementMethod(ScrollingMovementMethod
.getInstance());// 使TextView接收区可以滚动
outcount = (TextView) findViewById(R.id.outcount);
incount = (TextView) findViewById(R.id.incount);
outcount.setText("0");
incount.setText("0");
mSendButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
// 使用编辑文本小部件的内容发送消息
TextView view = (TextView) findViewById(R.id.edit_text_out);
String message = view.getText().toString();
sendMessage(message);
}
});
// 初始化BluetoothChatService以执行app_incon_bluetooth连接
mChatService = new BluetoothChatService(this, mHandler);
//初始化外发消息的缓冲区
mOutStringBuffer = new StringBuffer("");
}
//重写发送函数,参数不同。
private void sendMessage(String message) {
// 确保已连接
if (mChatService.getState() != BluetoothChatService.STATE_CONNECTED) {
Toast.makeText(this, R.string.not_connected, Toast.LENGTH_SHORT)
.show();
return;
}
// 检测是否有字符串发送
if (message.length() > 0) {
// 获取 字符串并告诉BluetoothChatService发送
if (outhex == true) {
byte[] send = Data_syn.hexStr2Bytes(message);
mChatService.write(send);//回调service
} else if (outhex == false) {
byte[] send = message.getBytes();
mChatService.write(send);//回调service
}
// 清空输出缓冲区
mOutStringBuffer.setLength(0);
}
else {
Toast.makeText(this,"发送内容不能为空",
Toast.LENGTH_SHORT).show();
}
}
// 该Handler从BluetoothChatService中获取信息
private final Handler mHandler = new Handler() {
@Override
public 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);
mConversationView.setText(null);
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;
// 自动发送
if (auto == true) {
// 自动发送模块
mHandler.postDelayed(runnable, 1000);
} else if (auto == false) {
mHandler.removeCallbacks(runnable);
}
// 发送计数
if (outhex == true) {
String writeMessage = Data_syn.Bytes2HexString(writeBuf);
countout += writeMessage.length() / 2;
outcount.setText("" + countout);
} else if (outhex == false) {
String writeMessage = null;
try {
writeMessage = new String(writeBuf, "GBK");
} catch (UnsupportedEncodingException e1) {
e1.printStackTrace();
}
countout += writeMessage.length();
outcount.setText("" + countout);
}
break;
case MESSAGE_READ:
byte[] readBuf = (byte[]) msg.obj;
//检错误码计算函数
if (inhex == true) {
String readMessage = " "
+ Data_syn.bytesToHexString(readBuf, msg.arg1);
fmsg += readMessage;
mConversationView.append(readMessage);
// 接收计数,更显UI
countin += readMessage.length() / 2;
incount.setText("" + countin);
} else if (inhex == false) {
String readMessage = null;
try {
readMessage = new String(readBuf, 0, msg.arg1, "GBK");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
fmsg += readMessage;
mConversationView.append(readMessage);
// 接收计数,更新UI
countin += readMessage.length();
incount.setText("" + countin);
}
break;
case MESSAGE_DEVICE_NAME:
// 保存已连接设备的名称
mConnectedDeviceName = msg.getData().getString(DEVICE_NAME);
Toast.makeText(getApplicationContext(),
"连接到 " + mConnectedDeviceName, Toast.LENGTH_SHORT)
.show();
break;
case MESSAGE_TOAST:
Toast.makeText(getApplicationContext(),
msg.getData().getString(TOAST), Toast.LENGTH_SHORT)
.show();
break;
}
}
};
//返回该Activity回调函数
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (D)
Log.d(TAG, "onActivityResult " + resultCode);
switch (requestCode) {
//search返回的
case REQUEST_CONNECT_DEVICE:
// DeviceListActivity返回时要连接的设备
if (resultCode == Activity.RESULT_OK) {
// 获取设备的MAC地址
String address = data.getExtras().getString(
device.EXTRA_DEVICE_ADDRESS);
// 获取BLuetoothDevice对象
BluetoothDevice device = mBluetoothAdapter
.getRemoteDevice(address);
// 尝试连接到设备
mChatService.connect(device);
}
break;
//start返回的(遇到蓝牙不可用退出)
case REQUEST_ENABLE_BT:
// 当启用蓝牙的请求返回时
if (resultCode == Activity.RESULT_OK)
{
//蓝牙已启用,因此设置聊天会话
setupChat();//初始化文本
}
else
{
// 用户未启用蓝牙或发生错误
Log.d(TAG, "BT not enabled");
Toast.makeText(this, R.string.bt_not_enabled_leaving,
Toast.LENGTH_SHORT).show();
finish();
}
}
}
// 保存按键响应函数
public void onSaveButtonClicked(View v) {
Save();
}
// 清屏按键响应函数
public void onClearButtonClicked(View v) {
fmsg = "";
mConversationView.setText(null);
view.setText(null);
return;
}
// 清除计数按键响应函数
public void onClearCountButtonClicked(View v) {
countin = 0;
countout = 0;
outcount.setText("0");
incount.setText("0");
return;
}
// 保存功能实现
private void Save() {
// 显示对话框输入文件名
LayoutInflater factory = LayoutInflater.from(BluetoothChat.this); // 图层模板生成器句柄
final View DialogView = factory.inflate(R.layout.sname, null); // 用sname.xml模板生成视图模板
new AlertDialog.Builder(BluetoothChat.this).setTitle("文件名")
.setView(DialogView) // 设置视图模板
.setPositiveButton("确定", new DialogInterface.OnClickListener() // 确定按键响应函数
{
public void onClick(DialogInterface dialog,
int whichButton) {
EditText text1 = (EditText) DialogView
.findViewById(R.id.sname); // 得到文件名输入框句柄
filename = text1.getText().toString(); // 得到文件名
try {
if (Environment.getExternalStorageState()
.equals(Environment.MEDIA_MOUNTED)) { // 如果SD卡已准备好
filename = filename + ".txt"; // 在文件名末尾加上.txt
File sdCardDir = Environment
.getExternalStorageDirectory(); // 得到SD卡根目录
File BuildDir = new File(sdCardDir,
"/BluetoothSave"); // 打开BluetoothSave目录,如不存在则生成
if (BuildDir.exists() == false)
BuildDir.mkdirs();
File saveFile = new File(BuildDir,
filename); // 新建文件句柄,如已存在仍新建文档
FileOutputStream stream = new FileOutputStream(
saveFile); // 打开文件输入流
stream.write(fmsg.getBytes());
stream.close();
Toast.makeText(BluetoothChat.this,
"存储成功!", Toast.LENGTH_SHORT)
.show();
} else {
Toast.makeText(BluetoothChat.this,
"没有存储卡!", Toast.LENGTH_LONG)
.show();
}
} catch (IOException e) {
return;
}
}
})
.setNegativeButton("取消", // 取消按键响应函数,直接退出对话框不做任何处理
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog,
int which) {
}
}).show(); // 显示对话框
}
@Override
public synchronized void onResume() {
super.onResume();
if (D)
Log.e(TAG, "+ ON RESUME +");
// 在onResume()中执行此检查包括在onStart()期间未启用BT的情况,
// 因此我们暂停启用它...
// onResume()将在ACTION_REQUEST_ENABLE活动时被调用返回.
if (mChatService != null) {
// 只有状态是STATE_NONE,我们知道我们还没有启动蓝牙
if (mChatService.getState() == BluetoothChatService.STATE_NONE) {
// 启动BluetoothChat服务
mChatService.start();
}
}
}
@Override
public synchronized void onPause() {
super.onPause();
if (D)
Log.e(TAG, "- ON PAUSE -");
}
@Override
public void onStop() {
super.onStop();
if (D)
Log.e(TAG, "-- ON STOP --");
}
@Override
public void onDestroy() {
super.onDestroy();
// 停止蓝牙通信连接服务
if (mChatService != null)
mChatService.stop();
if (D)
Log.e(TAG, "--- ON DESTROY ---");
}
@Override
public void onBackPressed()
{
exit();
}
public void exit()
{
exit = true;
if(exit == true)
{
this.finish();
}
}
}
DeviceListActivity.class,蓝牙配对列表显示,点击返回给主界面,主要为一个listview
/**
* 这个 Activity显示为一个对话框. 它列出了所有已配对的设备和之后在该地区搜索到的设备. 当一个设备被用户选择后,
* 该设备的MAC地址会在result Intent中被传回到父 Activity.
*/
public class DeviceListActivity extends Activity
{
// Debugging
private static final String TAG = "DeviceListActivity";
private static final boolean D = true;
// Return Intent extra
public static String EXTRA_DEVICE_ADDRESS = "device_address";
public static String EXTRA_LEGAL = "legal";
// Member fields
private BluetoothAdapter mBtAdapter;
private ArrayAdapter mPairedDevicesArrayAdapter;
private ArrayAdapter mNewDevicesArrayAdapter;
private boolean isexist =false;
//自动配对结果
private boolean result=false;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
// 设置窗口
requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
setContentView(R.layout.device_list);
// 设置结果CANCELED使用户退出
setResult(Activity.RESULT_CANCELED);
// 初始化阵列适配器。 一个用于已配对的设备,一个用于新发现的设备,一个用于测试专用的设备
mPairedDevicesArrayAdapter = new ArrayAdapter(this,
R.layout.device_name);
mNewDevicesArrayAdapter = new ArrayAdapter(this,
R.layout.device_name);
// 为配对的设备查找和设置ListView
ListView pairedListView = (ListView) findViewById(R.id.paired_devices);
pairedListView.setAdapter(mPairedDevicesArrayAdapter);
pairedListView.setOnItemClickListener(mDeviceClickListener);
// 为新发现的设备找到并设置ListView
ListView newDevicesListView = (ListView) findViewById(R.id.new_devices);
newDevicesListView.setAdapter(mNewDevicesArrayAdapter);
newDevicesListView.setOnItemClickListener(mDeviceClickListener);
// 发现设备时注册广播
IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
this.registerReceiver(mReceiver, filter);
// 发现完成后注册广播
filter = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
this.registerReceiver(mReceiver, filter);
//自动配对请求注册广播
filter = new IntentFilter(BluetoothDevice.ACTION_PAIRING_REQUEST);
this.registerReceiver(mReceiver, filter);
// 获取本地蓝牙适配器
mBtAdapter = BluetoothAdapter.getDefaultAdapter();
// 获取一组当前配对的设备
Set pairedDevices = mBtAdapter.getBondedDevices();
// 如果有配对的设备,请将每个设备添加到ArrayAdapter
TextView textView = (TextView) findViewById(R.id.title_paired_devices);
if (pairedDevices.size() > 0)
{
textView.setVisibility(View.VISIBLE);
for (BluetoothDevice device : pairedDevices)
{ isexist=true;
mPairedDevicesArrayAdapter.add(device.getName() + "\n"
+ device.getAddress());
}
}
if (isexist==false)
{
textView.setVisibility(View.GONE);
String noDevices = getResources().getText(R.string.none_paired)
.toString();
mPairedDevicesArrayAdapter.add(noDevices);
}
}
@Override
protected void onStart() {
super.onStart();
doDiscovery();
}
@Override
protected void onDestroy()
{
super.onDestroy();
// 确保我们不再进行发现
if (mBtAdapter != null)
{
mBtAdapter.cancelDiscovery();
}
//取消注册广播侦听器
this.unregisterReceiver(mReceiver);
}
/**
* 使用BluetoothAdapter启动设备发现
*/
private void doDiscovery()
{
if (D) Log.d(TAG, "doDiscovery()");
// 在标题中指示扫描
setProgressBarIndeterminateVisibility(true);
setTitle(R.string.scanning);
// 开启新装置的副标题
findViewById(R.id.title_new_devices).setVisibility(View.VISIBLE);
// 如果我们已经发现,停止它
if (mBtAdapter.isDiscovering())
{
mBtAdapter.cancelDiscovery();
}
//从BluetoothAdapter请求发现
mBtAdapter.startDiscovery();
}
// ListView中其他设备的点击监听器
private OnItemClickListener mDeviceClickListener = new OnItemClickListener()
{
public void onItemClick(AdapterView> av, View v, int arg2, long arg3)
{
//取消发现,我们m_about来连接
mBtAdapter.cancelDiscovery();
// 获取设备的MAC地址,这是视图中最后17个字符
String info = ((TextView) v).getText().toString();
String address = info.substring(info.length() - 17);
// 创建结果意图并包括MAC地址
Intent intent = new Intent();
intent.putExtra(EXTRA_DEVICE_ADDRESS, address);
intent.putExtra(EXTRA_LEGAL,false);
// 设置结果并完成此活动
setResult(Activity.RESULT_OK, intent);
finish();
}
};
//ListView中专用测试设备的点击监听器
private OnItemClickListener mZYDeviceClickListener = new OnItemClickListener() {
@Override
public void onItemClick(AdapterView> parent, View view, int position, long id) {
//取消发现,我们m_about来连接
mBtAdapter.cancelDiscovery();
// 获取设备的MAC地址,这是视图中最后17个字符
String info = ((TextView) view).getText().toString();
String address = info.substring(info.length() - 17);
// 创建结果意图并包括MAC地址
Intent intent = new Intent();
intent.putExtra(EXTRA_DEVICE_ADDRESS, address);
intent.putExtra(EXTRA_LEGAL,true);
// 设置结果并完成此活动
setResult(Activity.RESULT_OK, intent);
finish();
}
};
// BroadcastReceiver,侦听发现的设备,并在发现完成时更改标题
private final BroadcastReceiver mReceiver = new BroadcastReceiver()
{
@Override
public void onReceive(Context context, Intent intent)
{
String action = intent.getAction();
//从Intent获取BluetoothDevice对象
BluetoothDevice device = intent
.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
// 发现找到设备时
if (BluetoothDevice.ACTION_FOUND.equals(action))
{ String devicename =device.getName();
while (devicename==null){
devicename =device.getName();
}
// 该设备没有配对,加载到新的通用蓝牙设备的列表
if (device.getBondState() != BluetoothDevice.BOND_BONDED)
{
mNewDevicesArrayAdapter.add(device.getName() + "\n"
+ device.getAddress());
}
// 再次得到的action,会等于PAIRING_REQUEST,进行配对操作
}else if(BluetoothDevice.ACTION_PAIRING_REQUEST.equals(action)){
String devicename =device.getName();
while (devicename==null){
devicename =device.getName();
}
Log.e(TAG,"接收到配对广播");
}
// 发现完成后,更改活动标题
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);
}
}
}
};
数据转换工具类 主要设置十六进制数据为ascll数据的转化
// 将字节数组转化为16进制字符串,确定长度
public static String bytesToHexString(byte[] bytes, int a) {
String result = "";
for (int i = 0; i < a; i++) {
String hexString = Integer.toHexString(bytes[i] & 0xFF);// 将高24位置0
if (hexString.length() == 1) {
hexString = '0' + hexString;
}
result += hexString.toUpperCase();
}
return result;
}
// 将字节数组转化为16进制字符串,不确定长度
public static String Bytes2HexString(byte[] b) {
String ret = "";
for (int i =0; i < b.length; i++) {
String hex = Integer.toHexString(b[i] & 0xFF);// 将高24位置0
if (hex.length() == 1) {
hex = '0' + hex;
}
ret += hex.toUpperCase();
}
return ret;
}
// 将16进制字符串转化为字节数组
public static byte[] hexStr2Bytes(String paramString) {
int i = paramString.length() / 2;
byte[] arrayOfByte = new byte[i];
int j = 0;
while (true) {
if (j >= i)
return arrayOfByte;
int k = 1 + j * 2;
int l = k + 1;
arrayOfByte[j] = (byte) (0xFF & Integer.decode(
"0x" + paramString.substring(j * 2, k)
+ paramString.substring(k, l)).intValue());
++j;
}
}
最后附上运行的app界面截图