热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Android学习笔记之蓝牙通信...

PS:最近同学问我蓝牙的事,因此自己也就脑补了一下蓝牙 学习内容:1.如何实现蓝牙通信技术  蓝牙通信其实是手机里很常用的一种通信方式,现在的手机中是必然存在蓝牙的,蓝

PS:最近同学问我蓝牙的事,因此自己也就脑补了一下蓝牙...

 

学习内容:

1.如何实现蓝牙通信技术...

 

  蓝牙通信其实是手机里很常用的一种通信方式,现在的手机中是必然存在蓝牙的,蓝牙通信也是有一部分优点的,功耗低,安全性比较高,但是缺点想必大家都知道,传输的速率也确实是不快,相比于Wifi通信,确实不值一提...虽然影响范围并不高,但是既然蓝牙存在,那么还是有必要知道蓝牙是如何进行通信的...蓝牙通信有两种方式,最常用的就是使用socket套接字来实现蓝牙通信...

  蓝牙通信原理:蓝牙通信的原理很简单,一个设备作为服务端,另一个设备作为客户端,服务端对外暴露,客户端通过发送连接请求,服务端进行响应,然后返回一个BluetoothSocket套接字来管理这个连接...那么服务端个客户端就会共享一个RFCOMM端口,进行数据传递...听起来其实蛮简单的,实现过程还是有点复杂的...这里我还是直接上一个代码吧...

  这个是Activity.java文件...这是个非常长的代码块,看完谁都头痛...我们还是进行分块解释...先把这些代码都略过...还是看最下面的解释...

package com.qualcomm.bluetoothclient;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Set;
import java.util.UUID;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.inputmethod.InputMethodManager;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.Toast;
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
public class ClientActivity extends Activity implements OnItemClickListener {
private Context mContext;
private BluetoothAdapter mBluetoothAdapter; // Bluetooth适配器
private BluetoothDevice device; // 蓝牙设备
private ListView mListView;
private ArrayList list;
private ClientAdapter clientAdapter; // ListView适配器
private Button discOnnect= null, sendButton = null;
private EditText editText = null;

private BluetoothSocket socket; // 客户端socket
private ClientThread mClientThread; // 客户端运行线程
private ReadThread mReadThread; // 读取流线程

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

init();
}
// 变量初始化
private void init() {
// TODO Auto-generated method stub
mCOntext= this;
mBluetoothAdapter
= BluetoothAdapter.getDefaultAdapter();//获取本地蓝牙...

list
= new ArrayList();// 初始化list
clientAdapter = new ClientAdapter(mContext, list); //适配器,用来限制如何显示ListView...
mListView = (ListView) findViewById(R.id.list);

mListView.setFastScrollEnabled(
true);

mListView.setAdapter(clientAdapter);

mListView.setOnItemClickListener(
this);

// 注册receiver监听,注册广播...
IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
registerReceiver(mReceiver, filter);

// 获取已经配对过的蓝牙设备
Set pairedDevices = mBluetoothAdapter.getBondedDevices();//获取发现的蓝牙设备的基本信息...

if (pairedDevices.size() > 0) {
for (BluetoothDevice device : pairedDevices) {
//将手机名字和物理地址放入到listview中...
list.add(new ChatMessage(device.getName() + "\n" + device.getAddress(), true));

clientAdapter.notifyDataSetChanged();
//重新绘制ListView

mListView.setSelection(list.size()
- 1);
}
}
else {
list.add(
new ChatMessage("没有已经配对过的设备", true));
clientAdapter.notifyDataSetChanged();
mListView.setSelection(list.size()
- 1);
}

editText
= (EditText) findViewById(R.id.edit);
editText.setEnabled(
false);
editText.clearFocus();

sendButton
= (Button) findViewById(R.id.btn_send);
sendButton.setEnabled(
false);
sendButton.setOnClickListener(
new OnClickListener() {

@Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
String msg = editText.getText().toString();
if (msg.length() > 0) {
sendMessageHandler(msg);
editText.setText(
"");
editText.clearFocus();
InputMethodManager imm
= (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);//定义一个输入法对象...通过Context.INPUT_METHOD_SERVICE获取实例...
//当EditText没有焦点的时候,阻止输入法的弹出...其实就是在没点击EditText获取焦点的时候,没有输入法的显示...
imm.hideSoftInputFromWindow(editText.getWindowToken(), 0);
}
else {
Toast.makeText(mContext,
"发送内容不能为空", Toast.LENGTH_SHORT).show();
}
}
});

disconnect
= (Button) findViewById(R.id.disconnect);
disconnect.setEnabled(
false);
disconnect.setOnClickListener(
new OnClickListener() {

@Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
// 关闭相关服务
closeClient();
BluetoothMsg.isOpen
= false;

BluetoothMsg.serviceOrCilent
= BluetoothMsg.ServerOrCilent.NONE;
Toast.makeText(mContext,
"连接已断开", Toast.LENGTH_SHORT).show();
}
});
}

@Override
protected void onStart() {
// TODO Auto-generated method stub
super.onStart();
if (mBluetoothAdapter != null) { //本地蓝牙存在...
if (!mBluetoothAdapter.isEnabled()) { //判断蓝牙是否被打开...
// 发送打开蓝牙的意图,系统会弹出一个提示对话框
Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableIntent, RESULT_FIRST_USER);

// 设置蓝牙的可见性,最大值3600秒,默认120秒,0表示永远可见(作为客户端,可见性可以不设置,服务端必须要设置)

//打开本机的蓝牙功能,持续的时间是永远可见...
Intent displayIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
displayIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION,
0);
startActivity(displayIntent);

// 直接打开蓝牙
mBluetoothAdapter.enable();
}
}
}

@Override
protected void onResume() {
// TODO Auto-generated method stub
super.onResume();
// 扫描
scanDevice();
}

/**
* 蓝牙设备扫描过程中(mBluetoothAdapter.startDiscovery())会发出的消息
* ACTION_FOUND 扫描到远程设备
* ACTION_DISCOVERY_FINISHED 扫描结束
*/
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
// 通过EXTRA_DEVICE附加域来得到一个BluetoothDevice设备
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);

// If it\'s already paired, skip it, because it\'s been listed already
// 如果这个设备是不曾配对过的,添加到list列表
if (device.getBondState() != BluetoothDevice.BOND_BONDED)
{
list.add(
new ChatMessage(device.getName() + "\n" + device.getAddress(), false));
clientAdapter.notifyDataSetChanged();
mListView.setSelection(list.size()
- 1);
}
// When discovery is finished, change the Activity title
}
else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action))
{
setProgressBarIndeterminateVisibility(
false);
if (mListView.getCount() == 0)
{
list.add(
new ChatMessage("没有发现蓝牙设备", false));
clientAdapter.notifyDataSetChanged();
mListView.setSelection(list.size()
- 1);
}
}
}
};

// Handler更新UI
private Handler LinkDetectedHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
//Toast.makeText(mContext, (String)msg.obj, Toast.LENGTH_SHORT).show();
if(msg.what==1)
{
list.add(
new ChatMessage((String)msg.obj, true));
}
else
{
list.add(
new ChatMessage((String)msg.obj, false));
}
clientAdapter.notifyDataSetChanged();
mListView.setSelection(list.size()
- 1);

}

};

// 当连接上服务器的时候才可以选择发送数据和断开连接
private Handler refreshUI = new Handler() {
public void handleMessage(Message msg) {
if (msg.what == 0) {
disconnect.setEnabled(
true);
sendButton.setEnabled(
true);
editText.setEnabled(
true);
}
}
};

// 开启客户端连接服务端
private class ClientThread extends Thread {
@Override
public void run() {
// TODO Auto-generated method stub
if (device != null) {
try {
socket
= device.createRfcommSocketToServiceRecord(UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"));
// 连接
Message msg = new Message();
msg.obj
= "请稍候,正在连接服务器: "+ BluetoothMsg.BlueToothAddress;
msg.what
= 0;
LinkDetectedHandler.sendMessage(msg);
// 通过socket连接服务器,这是一个阻塞过程,直到连接建立或者连接失效
socket.connect();
Message msg2
= new Message();
msg2.obj
= "已经连接上服务端!可以发送信息";
msg2.what
= 0;
LinkDetectedHandler.sendMessage(msg2);
// 更新UI界面
Message uiMessage = new Message();
uiMessage.what
= 0;
refreshUI.sendMessage(uiMessage);
// 可以开启读数据线程
mReadThread = new ReadThread();
mReadThread.start();
}
catch (IOException e) {
// TODO Auto-generated catch block
// socket.connect()连接失效
Message msg = new Message();
msg.obj
= "连接服务端异常!断开连接重新试一试。";
msg.what
= 0;
LinkDetectedHandler.sendMessage(msg);
}
}
}
}

// 通过socket获取InputStream流
private class ReadThread extends Thread {
@Override
public void run() {
// TODO Auto-generated method stub
byte[] buffer = new byte[1024];
int bytes;
InputStream is
= null;
try {
is
= socket.getInputStream();
}
catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
while(true) {
try {
if ((bytes = is.read(buffer)) > 0) {
byte[] data = new byte[bytes];
for (int i = 0; i ) {
data[i] = buffer[i];
}
String s
= new String(data);
Message msg
= new Message();
msg.obj
= s;
msg.what
= 1;
LinkDetectedHandler.sendMessage(msg);
}
}
catch (IOException e) {
// TODO Auto-generated catch block
try {
is.close();
}
catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
break;
}
}
}
}

// 发送数据
private void sendMessageHandler(String msg) {
if (socket == null) {
Toast.makeText(mContext,
"没有可用的连接", Toast.LENGTH_SHORT).show();
return;
}
//如果连接上了,那么获取输出流...
try {
OutputStream os
= socket.getOutputStream();
os.write(msg.getBytes());
}
catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
list.add(
new ChatMessage(msg, false)); //将数据存放到list中
clientAdapter.notifyDataSetChanged();
mListView.setSelection(list.size()
- 1);
}

// 停止服务
private void closeClient() {
new Thread() {
public void run() {
if (mClientThread != null) {
mClientThread.interrupt();
mClientThread
= null;
}
if (mReadThread != null) {
mReadThread.interrupt();
mReadThread
= null;
}
try {
if (socket != null) {
socket.close();
socket
= null;
}
}
catch (IOException e) {
// TODO: handle exception
}
}
}.start();
}

// 扫描设备
private void scanDevice() {
// TODO Auto-generated method stub
if (mBluetoothAdapter.isDiscovering()) { //如果正在处于扫描过程...
mBluetoothAdapter.cancelDiscovery(); //取消扫描...
} else {
list.clear();
clientAdapter.notifyDataSetChanged();

// 每次扫描前都先判断一下是否存在已经配对过的设备
Set pairedDevices = mBluetoothAdapter.getBondedDevices();
if (pairedDevices.size() > 0) {
for (BluetoothDevice device : pairedDevices) {
list.add(
new ChatMessage(device.getName() + "\n" + device.getAddress(), true));
clientAdapter.notifyDataSetChanged();
mListView.setSelection(list.size()
- 1);
}
}
else {
list.add(
new ChatMessage("No devices have been paired", true));
clientAdapter.notifyDataSetChanged();
mListView.setSelection(list.size()
- 1);
}
/* 开始搜索 */
mBluetoothAdapter.startDiscovery();
}
}
@Override
public void onItemClick(AdapterView arg0, View arg1, int arg2, long arg3) {
// TODO Auto-generated method stub
ChatMessage item = list.get(arg2); //item保存着message和一个boolean数值...
String info = item.getMessage(); //单纯获取message的信息...

String address
= info.substring(info.length() - 17);//获取MAC地址...其实就是硬件地址...


BluetoothMsg.BlueToothAddress
= address;

// 停止扫描
// BluetoothAdapter.startDiscovery()很耗资源,在尝试配对前必须中止它
mBluetoothAdapter.cancelDiscovery();

// 通过Mac地址去尝试连接一个设备
device = mBluetoothAdapter.getRemoteDevice(BluetoothMsg.BlueToothAddress);
mClientThread
= new ClientThread(); //开启新的线程...
mClientThread.start();
BluetoothMsg.isOpen
= true;

}
@Override
protected void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
if (mBluetoothAdapter != null) {
mBluetoothAdapter.cancelDiscovery();
// 关闭蓝牙
mBluetoothAdapter.disable();
}
unregisterReceiver(mReceiver);
closeClient();
}
}

View Code

   这个是我自定义了一个类,用来判断蓝牙的连接类型...

package com.qualcomm.bluetoothclient;

public class BluetoothMsg {
/**
* 蓝牙连接类型
*
*/
public enum ServerOrCilent {
NONE,
SERVICE,
CILENT
};

//蓝牙连接方式
public static ServerOrCilent serviceOrCilent = ServerOrCilent.NONE;
//连接蓝牙地址
public static String BlueToothAddress = null, lastblueToothAddress = null;
//通信线程是否开启
public static boolean isOpen = false;

}

  这个是保存我们发送的数据信息的自定义类...

package com.qualcomm.bluetoothclient;
/*
* 这里定义一个类,用来保存我们发送的数据信息...
*
*/
public class ChatMessage {
private String message;
private boolean isSiri;

public ChatMessage(String message, boolean siri) {
// TODO Auto-generated constructor stub
this.message = message;
this.isSiri = siri;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public boolean isSiri() {
return isSiri;
}
public void setSiri(boolean isSiri) {
this.isSiri = isSiri;
}


}

  最后这个是适配器...因为我这里使用到了ListView,因此我需要使用一个适配器来设置ListView以何种方式显示在屏幕上...

package com.qualcomm.bluetoothclient;
import java.util.ArrayList;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;
/*
*



*
*/
public class ClientAdapter extends BaseAdapter {
private ArrayList list;
private LayoutInflater mInflater;

public ClientAdapter(Context context, ArrayList messages) {
// TODO Auto-generated constructor stub
this.list = messages;
this.mInflater = LayoutInflater.from(context);
}

@Override
public int getCount() {
// TODO Auto-generated method stub
return list.size();
}
@Override
public Object getItem(int position) {
// TODO Auto-generated method stub
return list.get(position);
}
@Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return position;
}

@Override
public int getItemViewType(int position) {
// TODO Auto-generated method stub
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
ViewHolder viewHolder = null;
ChatMessage message
= list.get(position);
if (cOnvertView== null) {
convertView
= mInflater.inflate(R.layout.list_item, null);
viewHolder
= new ViewHolder((View)convertView.findViewById(R.id.list_child)
, (TextView)convertView.findViewById(R.id.chat_msg));
convertView.setTag(viewHolder);
}
else {
viewHolder
= (ViewHolder) convertView.getTag();
}
if (message.isSiri()) {
viewHolder.child.setBackgroundResource(R.drawable.msgbox_rec);
}
else {
viewHolder.child.setBackgroundResource(R.drawable.msgbox_send);
}
viewHolder.msg.setText(message.getMessage());

return convertView;
}
class ViewHolder {
protected View child;
protected TextView msg;
public ViewHolder(View child, TextView msg){
this.child = child;
this.msg = msg;

}
}
}

  在这里我进行正式的解释...先说第二部分..第二部分是一些初始化的操作...也就是获取本地蓝牙,注册广播,设置监听的一些过程...因为实现通信,我们首先要判断我们的手机是否有蓝牙...获取到本机的蓝牙... 也就是这句话是实现通信的第一步...mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();我们才能够打开蓝牙...然后进行操作...详细解释在代码中...

//→_→ 第二部分...

// 变量初始化
private void init() {
// TODO Auto-generated method stub
mCOntext= this;
mBluetoothAdapter
= BluetoothAdapter.getDefaultAdapter();//获取本地蓝牙...实现通信的第一步...

list
= new ArrayList();// 初始化list,由于我们最后会将数据以列表的形式进行显示,因此使用ListView...
clientAdapter = new ClientAdapter(mContext, list); //适配器,用来限制如何显示ListView...

mListView
= (ListView) findViewById(R.id.list);

mListView.setFastScrollEnabled(
true); //使用快速滑动功能..目的是能够快速滑动到指定位置...

mListView.setAdapter(clientAdapter);

mListView.setOnItemClickListener(
this);

/* 下面是注册receiver监听,注册广播...说一下为什么要注册广播...
* 因为蓝牙的通信,需要进行设备的搜索,搜索到设备后我们才能够实现连接..如果没有搜索,那还谈什么连接...
* 因此我们需要搜索,搜索的过程中系统会自动发出三个广播...这三个广播为:
* ACTION_DISCOVERY_START:开始搜索...
* ACTION_DISCOVERY_FINISH:搜索结束...
* ACTION_FOUND:正在搜索...一共三个过程...因为我们需要对这三个响应过程进行接收,然后实现一些功能,因此
* 我们需要对广播进行注册...知道广播的人应该都知道,想要对广播进行接收,必须进行注册,否则是接收不到的...
*
*/
IntentFilter filter
= new IntentFilter(BluetoothDevice.ACTION_FOUND);
registerReceiver(mReceiver, filter);

// 定义一个集合,来保存已经配对过的设备...
Set pairedDevices = mBluetoothAdapter.getBondedDevices();

if (pairedDevices.size() > 0) { //如果存在设备...
for (BluetoothDevice device : pairedDevices) {//遍历...

//将手机名字和物理地址放入到listview中...
list.add(new ChatMessage(device.getName() + "\n" + device.getAddress(), true));

clientAdapter.notifyDataSetChanged();
//重新绘制ListView

mListView.setSelection(list.size()
- 1); //设置list保存的信息的位置...说白了该条信息始终在上一条信息的下方...
}
}
else {
list.add(
new ChatMessage("没有已经配对过的设备", true));
clientAdapter.notifyDataSetChanged();
mListView.setSelection(list.size()
- 1);
}

editText
= (EditText) findViewById(R.id.edit);
editText.setEnabled(
false);
editText.clearFocus();
//设置没有焦点..也就是无法输入任何文字...

sendButton
= (Button) findViewById(R.id.btn_send);
sendButton.setEnabled(
false);
sendButton.setOnClickListener(
new OnClickListener() {//设置监听,只有获取到焦点后才能进行此过程...

@Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
String msg = editText.getText().toString();

if (msg.length() > 0) {
//调用第五部分线程,通过线程发送我们输入的文本...
sendMessageHandler(msg);
//发送完清空...
editText.setText("");
editText.clearFocus();
InputMethodManager imm
= (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);//定义一个输入法对象...通过Context.INPUT_METHOD_SERVICE获取实例...
//当EditText没有焦点的时候,阻止输入法的弹出...其实就是在没点击EditText获取焦点的时候,没有输入法的显示...
imm.hideSoftInputFromWindow(editText.getWindowToken(), 0);
}
else {
Toast.makeText(mContext,
"发送内容不能为空", Toast.LENGTH_SHORT).show();
}
}
});

disconnect
= (Button) findViewById(R.id.disconnect);
disconnect.setEnabled(
false);
//为断开连接设置监听...
disconnect.setOnClickListener(new OnClickListener() {

@Override
public void onClick(View arg0) {
// TODO Auto-generated method stub

// 关闭相关服务,调用第六部分的函数...
closeClient();
//表示蓝牙状态需要关闭...
BluetoothMsg.isOpen = false;

BluetoothMsg.serviceOrCilent
= BluetoothMsg.ServerOrCilent.NONE;
Toast.makeText(mContext,
"连接已断开", Toast.LENGTH_SHORT).show();
}
});
}

  接着就是第三部分了...我们获取到了本地的蓝牙设备,我们就需要把蓝牙进行打开了..只有开启了蓝牙,才能够进行搜索,连接等操作..因此这一步是实现蓝牙通信的关键...

//→_→ 第三部分...
@Override
protected void onStart() {
// TODO Auto-generated method stub
super.onStart();
if (mBluetoothAdapter != null) { //本地蓝牙存在...
if (!mBluetoothAdapter.isEnabled()) { //判断蓝牙是否被打开...

// 发送打开蓝牙的意图,系统会弹出一个提示对话框,打开蓝牙是需要传递intent的...
// intent这个重要的东西,大家应该都知道,它能够实现应用之间通信和交互....
Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
//打开本机的蓝牙功能...使用startActivityForResult()方法...这里我们开启的这个Activity是需要它返回执行结果给主Activity的...
startActivityForResult(enableIntent, RESULT_FIRST_USER);


Intent displayIntent
= new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
// 设置蓝牙的可见性,最大值3600秒,默认120秒,0表示永远可见(作为客户端,可见性可以不设置,服务端必须要设置)
displayIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 0);
//这里只需要开启另一个activity,让其一直显示蓝牙...没必要把信息返回..因此调用startActivity()
startActivity(displayIntent);

// 直接打开蓝牙
mBluetoothAdapter.enable();//这步才是真正打开蓝牙的部分....
}
}
}

//这步就是当线程从Pause状态到Avtive状态要执行的过程...
@Override
protected void onResume() {
// TODO Auto-generated method stub
super.onResume();
// 扫描
scanDevice(); //调用第七部分的扫描过程...
}

  然后是第四部分....第四部分是对广播响应后的接收过程..这个过程也是重要的,因为我们在开启蓝牙后扫描的时候,如果有设备可以连接,我们得做一些操作让用户知道有设备可以连接,总不能有设备连接,我们什么也不告诉用户,这就不合理吧....因此我们在这一步是需要给用户反馈信息的...让用户知道下一步应该做什么...这一部分倒是很简单,没复杂的东西..

//→_→ 第四部分...
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {

String action
= intent.getAction(); //获取当前正在执行的动作...
if (BluetoothDevice.ACTION_FOUND.equals(action)) //正在搜索过程...
{
// 通过EXTRA_DEVICE附加域来得到一个BluetoothDevice设备
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);

// 如果这个设备是不曾配对过的,添加到list列表
if (device.getBondState() != BluetoothDevice.BOND_BONDED)
{
list.add(
new ChatMessage(device.getName() + "\n" + device.getAddress(), false));
clientAdapter.notifyDataSetChanged();
mListView.setSelection(list.size()
- 1);
}
}
else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) //搜索结束后的过程...
{
setProgressBarIndeterminateVisibility(
false); //这步是如果设备过多是否显示滚动条...
if (mListView.getCount() == 0)
{
list.add(
new ChatMessage("没有发现蓝牙设备", false));
clientAdapter.notifyDataSetChanged();
mListView.setSelection(list.size()
- 1);
}
}
}
};

  第五部分就是线程部分了,所有的线程部分...涉及UI的更新,数据信息的显示,将数据进行发送,接收服务器返回的数据信息...这步是实现数据传递的关键...

//→_→ 第五部分...

private Handler LinkDetectedHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
//这步多了一个判断..判断的是ListView保存的数据是我们要传输给服务端的数据,还是那些我们定义好的提示数据...
if(msg.what==1)
{
list.add(
new ChatMessage((String)msg.obj, true));
}
else
{
list.add(
new ChatMessage((String)msg.obj, false));
}
clientAdapter.notifyDataSetChanged();
mListView.setSelection(list.size()
- 1);

}

};
// Handler更新UI...
// 当连接上服务器的时候才可以选择发送数据和断开连接,并且要对界面进行刷新操作...
private Handler refreshUI = new Handler() {
public void handleMessage(Message msg) {
if (msg.what == 0) {
disconnect.setEnabled(
true);
sendButton.setEnabled(
true);
editText.setEnabled(
true);
}
}
};

// 开启客户端连接服务端,一个新的线程...
private class ClientThread extends Thread {
@Override
public void run() {
// TODO Auto-generated method stub
if (device != null) {
try {
/* 下面这步也是关键,我们如果想要连接服务器,我们需要调用方法createRfcommSocketToServiceRecord
* 参数00001101-0000-1000-8000-00805F9B34FB表示的是默认的蓝牙串口...通过传递参数调用方法,
* 会返回给我们一个套接字..这一步就是获取套接字,实现连接的过程...
*
*
*/
socket
= device.createRfcommSocketToServiceRecord(UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"));
// 连接
Message msg = new Message();
msg.obj
= "请稍候,正在连接服务器: "+ BluetoothMsg.BlueToothAddress;
msg.what
= 0;
LinkDetectedHandler.sendMessage(msg);
//调用线程,显示msg信息...
// 通过socket连接服务器,正式形成连接...这是一个阻塞过程,直到连接建立或者连接失效...
socket.connect();
//如果实现了连接,那么服务端和客户端就共享一个RFFCOMM信道...
Message msg2 = new Message();
msg2.obj
= "已经连接上服务端!可以发送信息";
msg2.what
= 0;
LinkDetectedHandler.sendMessage(msg2);
//调用线程,显示msg信息...
// 如果连接成功了...这步就会执行...更新UI界面...否则走catch(IOException e)
Message uiMessage = new Message();
uiMessage.what
= 0;
refreshUI.sendMessage(uiMessage);
// 可以开启读数据线程
mReadThread = new ReadThread();
mReadThread.start();
}
catch (IOException e) {
// TODO Auto-generated catch block
// socket.connect()连接失效
Message msg = new Message();
msg.obj
= "连接服务端异常!断开连接重新试一试。";
msg.what
= 0;
LinkDetectedHandler.sendMessage(msg);
}
}
}
}

// 通过socket获取InputStream流..
private class ReadThread extends Thread {
@Override
public void run() {
// TODO Auto-generated method stub

byte[] buffer = new byte[1024];
int bytes;
InputStream is
= null;
try {
is
= socket.getInputStream(); //获取服务器发过来的所有字节...
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
while(true) {
try {//读取过程,将数据信息保存在ListView中...
if ((bytes = is.read(buffer)) > 0) {
byte[] data = new byte[bytes];
for (int i = 0; i ) {
data[i] = buffer[i];
}
String s
= new String(data);
Message msg
= new Message();
msg.obj
= s;
msg.what
= 1; //这里的meg.what=1...表示的是服务器发送过来的数据信息..
LinkDetectedHandler.sendMessage(msg);
}
}
catch (IOException e) {
// TODO Auto-generated catch block
try {
is.close();
}
catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
break;
}
}
}
}
//这一步表示的是发送数据的过程...
private void sendMessageHandler(String msg) {
if (socket == null) {
Toast.makeText(mContext,
"没有可用的连接", Toast.LENGTH_SHORT).show();
return;
}
//如果连接上了,那么获取输出流...
try {
OutputStream os
= socket.getOutputStream();
os.write(msg.getBytes());
//获取所有的自己然后往外发送...
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
list.add(
new ChatMessage(msg, false)); //将数据存放到list中
clientAdapter.notifyDataSetChanged();
mListView.setSelection(list.size()
- 1);
}

  第六部分就是一个停止服务的一个过程,就不细说了,第七部分就是一个扫描的过程,扫描附近的设别...

// →_→ 第七部分...
// 扫描设备
private void scanDevice() {
// TODO Auto-generated method stub
if (mBluetoothAdapter.isDiscovering()) { //如果正在处于扫描过程...
mBluetoothAdapter.cancelDiscovery(); //取消扫描...
} else {
list.clear();
clientAdapter.notifyDataSetChanged();

// 每次扫描前都先判断一下是否存在已经配对过的设备
Set pairedDevices = mBluetoothAdapter.getBondedDevices();
if (pairedDevices.size() > 0) { //如果存在配对过的设备,那么就直接遍历集合,然后显示..
for (BluetoothDevice device : pairedDevices) {
list.add(
new ChatMessage(device.getName() + "\n" + device.getAddress(), true));
clientAdapter.notifyDataSetChanged();
mListView.setSelection(list.size()
- 1);
}
}
else { //如果没有就进行添加...
list.add(new ChatMessage("No devices have been paired", true));
clientAdapter.notifyDataSetChanged();
mListView.setSelection(list.size()
- 1);
}
/* 开始搜索 */
mBluetoothAdapter.startDiscovery();
}
}

  第八部分为连接过程做了一些初始化的工作,获取其他设备的物理地址,通过物理地址实现连接...至于第九部分就是销过程了,第一部分就是变量的定义过程...就没什么好说的了...

//→_→ 第八部分...
@Override
public void onItemClick(AdapterView arg0, View arg1, int arg2, long arg3) {
// TODO Auto-generated method stub
ChatMessage item = list.get(arg2); //item保存着message和一个boolean数值...
String info = item.getMessage(); //单纯获取message的信息...

String address
= info.substring(info.length() - 17);//获取MAC地址...其实就是硬件地址...因为连接设别必然从物理地址下手...


BluetoothMsg.BlueToothAddress
= address;//赋值

// 停止扫描
// BluetoothAdapter.startDiscovery()很耗资源,在尝试配对前必须中止它
mBluetoothAdapter.cancelDiscovery();

// 通过Mac地址去尝试连接一个设备,
device = mBluetoothAdapter.getRemoteDevice(BluetoothMsg.BlueToothAddress);

mClientThread
= new ClientThread();
mClientThread.start();
//开启新的线程...开始连接...这里只是做了一些初始化的工作..连接过程还是ClientThread线程...
BluetoothMsg.isOpen = true;

}

xml文件我就不贴了,直接放一个源码吧...这个源码包含一个客户端,一个服务端...(注意,这个测试需要在两个真机上测试,模拟器是没有作用的...)

源码地址:https://files.cnblogs.com/files/RGogoing/Bluetooth.zip

 



推荐阅读
author-avatar
jiangzh
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有