先上图:
客户端,创建socket,连接服务器,将服务器ip传给connect(),tcp/ip协议中,connect,需要的参数是一个ip,这里蓝牙的参数有所不同,连接完成后,就可读取和发送数据,最后关闭
服务端:连接前,也需要一个socket()有了socket后,我们还需要一个端口,用bind()绑定,端口号就是服务端的端口号。比如80端口,21端口等。。。绑定端口后,我们需要一个监听操作,tcp/ip中,listen()监听就是阻塞了,处于等待状态,当客户端发东西过来的时候,他会继续往下走,执行accept()函数,(阻塞发生下这里),它会常见新的socket来处理客户端的连接,也就是原来的socket继续监听,新创建的socket进行处理 ,来一个就新建一个socket来和客户端进行通信交互(体现了服务端的并发),同样发送,读取数据,处理完后,关闭连接,一边状态连接有客户端主动发起
服务端
1.listenUsingRfcommWithServiceRecord创建一个BluetoothServerSocket(是serverSoket)
2.监听网络accept
3。处理网络socket
4.关闭连接
客户端
1.creatRfcommWithServiceRecord创建一个BluetoothSocket(少了server)
2连接服务端connect
3。处理数据
4.关闭连接
等待连接,既进入监听状态。有小圆圈(进度条)在转(作为服务器)
客户端可以断开连接
我的代码结构图:
mainActivity:
package com.lmj.bluetoothdemo;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.Handler;
import android.support.annotation.RequiresApi;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.Window;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.Toast;
import com.lmj.bluetoothdemo.client.BluetoothController;
import com.lmj.bluetoothdemo.client.DeviceAdapter;
import com.lmj.bluetoothdemo.server.AcceptThread;
import com.lmj.bluetoothdemo.server.ConnectedThread;
import com.lmj.bluuetoothdemo.R;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private static final int REQUEST_CODE = 0;
private List<BluetoothDevice> mDeviceList = new ArrayList<>();
private List<BluetoothDevice> mBondedDeviceList = new ArrayList<>();
private BluetoothController mController = new BluetoothController();
private DeviceAdapter mAdapter;
private ListView mListView;
//这里是个延时创建
private Toast mToast;
private AcceptThread mAcceptThread;
private ConnectedThread mConnectThread;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
try {
initActionBar();
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
setContentView(R.layout.activity_main);
initUI();
registerBluetoothReceiver();
mController.turnOnBluetooth(this, REQUEST_CODE);
}
private void initActionBar() throws NoSuchFieldException {
requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
getActionBar().setDisplayUseLogoEnabled(false);
setProgressBarIndeterminate(true);
ViewConfiguration config=ViewConfiguration.get(this);
Field menuKeyField=ViewConfiguration.class.getDeclaredField("sHasPermanentMenuKey");
if(menuKeyField!=null){
}
}
private void registerBluetoothReceiver(){}
private Handler mUIHandler =new MyHandler();
/* private BroadcastReceiver mReceiver=(context,intent)->{
String action=intent.getAction();
if(BluetoothAdapter.ACTION_DISCOVERY_STARTED.equals(action)){
setProgressBarIndeterminateVisibility(true);
}
}*/
/* IntentFilter filter = new IntentFilter();
//在开始的时候需要注册一个处理蓝牙的广播
// IntentFilter filter=new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
//开始查找
filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED);
//结束查找
filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
//设备扫描模式改变,被看见有广播,不被看见也有广播过来
filter.addAction(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED);
//绑定状态
filter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
//注册广播
registerReceiver(mReceiver, filter);
mController.turnOnBluetooth(this, REQUEST_CODE);
}*/
private BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (BluetoothAdapter.ACTION_DISCOVERY_STARTED.equals(action)) {
//开始查找,查找上会有一个进度条,设别开始查找
setSupportProgressBarIndeterminateVisibility(true);
//初始数据列表
//设备清空
mDeviceList.clear();
//发送通知,关闭进度条等等
mAdapter.notifyDataSetChanged();
} else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) {
setSupportProgressBarIndeterminateVisibility(false);
}
//字符串的比较,有常量的放前面,可以防止为空报空指针异常的情况
//找到设备,就会有ACTION_FOUND这个广播,在广播的
else if (BluetoothDevice.ACTION_FOUND.equals(action)) {
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
//得device是我们查找的数据,找到一个,就添加一个
mDeviceList.add(device);
mAdapter.notifyDataSetChanged();
setSupportProgressBarIndeterminateVisibility(false);
} else if (BluetoothAdapter.ACTION_SCAN_MODE_CHANGED.equals(action)) {
//scanMode为SCAN_MODE_CONNECTABLE_DISCOVERABLE,就让他可见
int scanMode = intent.getIntExtra(BluetoothAdapter.EXTRA_SCAN_MODE, 0);
if (scanMode == BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
// 进度条转动,友好的人机交互,时间到了timeout就不可见。默认蓝牙扫描是12秒。
setProgressBarIndeterminateVisibility(true);
} else {
//进度条结束,设备不可见,通过ui给出提示,这比较友好,有互动,这就是广播的应用。
setProgressBarIndeterminateVisibility(false);
}
} else if (BluetoothDevice.ACTION_BOND_STATE_CHANGED.equals(action)) {
BluetoothDevice remoteDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
if (remoteDevice == null) {
showToast("没有设备");
return;
}
int status = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, 0);
if (status == BluetoothDevice.BOND_BONDED) {
}
}
}
};
public void isSupportBlueTooth(View view) {
boolean ret = mController.isSupportBlueTooth();
showToast("支持蓝牙" + ret);
}
public void isBlueToothEable(View view) {
boolean ret = mController.getBlueToothStatus();
showToast("蓝牙可用" + ret);
}
public void requestTurnOnBlueTooth(View view) {
mController.turnOnBluetooth(this, REQUEST_CODE);
// showToast("蓝牙可用"+ret);
}
public void turnOffBlueTooth(View view) {
mController.turnOffBlueTooth();
}
private void showToast(String text) {
if (mToast == null) {
mToast = Toast.makeText(this, text, Toast.LENGTH_SHORT);
} else {
mToast.setText(text);
}
mToast.show();
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == RESULT_OK) {
showToast("打开成功");
} else {
showToast("打开失败");
}
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.enable_visiblity) {
//打开蓝牙,使其可见,广播监听什么时候可见,什么时候不可见
mController.enableVisibly(this);
} else if (id == R.id.find_device) {
//查找设备
//每个设备点击后,都可进行绑定
mAdapter.refresh(mDeviceList);
mController.findDevice();
// 查找结果是通过广播传过来的
mListView.setOnItemClickListener(bindDeviceClick);
} else if (id == R.id.bonded_device) {
//查看已邦设备
//获取设备后,刷新
mBondedDeviceList = mController.getBondedDeviceList();
mAdapter.refresh(mBondedDeviceList);
//如果是完整流程,可以解绑定,将numl换成别的
mListView.setOnItemClickListener(null);
}
//启动了一个线程
else if (id==R.id.listening){
if(mAcceptThread!=null){
mAcceptThread.cancel();
}
mAcceptThread=new AcceptThread(mController.getAdapter(),mUIHandler, mBluetoothAdapter, mHandler);
mAcceptThread.start();
}
else if (id==R.id.stop_listening){
if(mAcceptThread!=null){
mAcceptThread.cancel();
}
}
else if (id==R.id.disconnect){
if(mAcceptThread!=null){
mConnectThread.cancel();
}
}
else if (id==R.id.say_hello){
say("hello");
}
return super.onOptionsItemSelected(item);
}
//客户端的起点在这里,点击绑定设备,
private AdapterView.OnItemClickListener bindDeviceClick = new AdapterView.OnItemClickListener() {
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
BluetoothDevice device = mDeviceList.get(i);
//每个设备,点一下,就创建绑定
if (mConnectThread!=null){
mConnectThread.cancel();
}
//这是客户端的连接,要连接的目标,adapter,以及把网络数据发给ui的一个连接
mConnectThread=new ConnectedThread(device,mController.getAdapter(),mUIHandler);
mConnectThread.start();
// device.createBond();
}
};
//手机蓝牙被其他设备所发现
}
constant:
package com.lmj.bluetoothdemo.server;
public class Constant {
//必须是B34FB结尾的uuid才可以
public static final String CONNECTTION_UUID="00001101-0000-8000-00805F9B34FB";
//开始监听
public static final int MSG_START_LISTENING=1;
//结束监听
public static final int MSG_FINISH_LISTENING=2;
/**
*有客户端连接
*/
public static final int MSG_GOT_A_CLINET=3;
/**
* 连接到服务器
*/
public static final int MSG_CONNECTED_TO_SERVER=4;
/**
* 获取到数据
*/
public static final int MSG_GOT_DATA=5;
/* public static final int MSG_START_LISTENING=1;
public static final int MSG_START_LISTENING=1;*/
}
ConnectThread:
package com.lmj.bluetoothdemo.server;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.os.Handler;
import java.io.IOException;
import java.util.UUID;
public class ConnectThread extends Thread {
private static final UUID MY_UUID = UUID.fromString(Constant.CONNECTTION_UUID);
private final BluetoothSocket mSocket;
private final BluetoothDevice mDevice;
private final BluetoothAdapter mBluetoothAdapter;
//和ui通信用的,将事件发送给ui,以为ui是不同的线程,
private final Handler mHandler;
//服务端新建线程,进行创建socket
private ConnectedThread mConnectedThread;
//private static final UUID MY
public ConnectThread(BluetoothSocket mSocket, BluetoothDevice mDevice, BluetoothAdapter mBluetoothAdapter, Handler handler) {
BluetoothSocket tmp = null;
this.mDevice = mDevice;
this.mSocket = mSocket;
this.mBluetoothAdapter = mBluetoothAdapter;
this.mHandler = handler;
try {
//整么的创建服务器端的socket,调用listenUsingRfcommWithServiceRecord方法创建,(常量,uuid必须是指定的)
//就是之前的uuid
tmp = mDevice.createRfcommSocketToServiceRecord(MY_UUID);
} catch (IOException E) {
}
mSocket = tmp;
}
public void run() {
//一边传输数据,一边发现设备,这是不行的,需先关闭发现设备,避免数据冲突,提升传输效率
mBluetoothAdapter.cancelDiscovery();
try {
mSocket.connect();
} catch (Exception connectException) {
mHandler.sendMessage(mHandler.obtainMessage(Constant.MSG_ERROR, connectException));
try {
mSocket.close();
} catch (IOException closeException) {
}
return;
}
managerConnectedSocket(mSocket);
}
private void managerConnectedSocket(BluetoothSocket mSocket){
//连上后进行数据处理,不管服务端,还是客户端,它发送数据的方式都是一样的
mHandler.sendEmptyMessage(Constant.MSG_CONNECTED_TO_SERVER);
mConnectedThread=new ConnectedThread(mSocket,mHandler);
mConnectedThread.start();
}
}
ConnectedThread:
package com.lmj.bluetoothdemo.server;
import android.bluetooth.BluetoothSocket;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
public class ConnectedThread extends Thread{
private final BluetoothSocket mSocket;
private final InputStream mInStream;
private final OutputStream mOutStream;
private final Handler mHandler;
public ConnectedThread(BluetoothSocket socket, Handler handler) {
mSocket=socket;
InputStream temIn=null;
OutputStream temOut=null;
mHandler=handler;
try{
temIn=socket.getInputStream();
temOut=socket.getOutputStream();
}catch (IOException e){}
mInStream=temIn;
mOutStream=temOut;
}
public void run(){
byte[] buffer=new byte[1024];
int bytes;
while (true){
//从网络里面读取数据
try {
bytes=mInStream.read(buffer);
//实际开发中,是将buffer通过handler交给listen(监听)来处理
if (bytes>0){
//将数据转为字符串,就是我们约定,网络通信的一个协议是Sring,故会将buffer强转为String,发给ui,ui会显示到屏幕上,
Message message=mHandler.obtainMessage(Constant.MSG_GOT_DATA,new String(buffer,0,bytes,"utf-8"));
mHandler.sendMessage(message);
}
Log.d("GOTMSG","mseeage size"+bytes);
} catch (IOException e) {
mHandler.sendMessage(mHandler.obtainMessage(Constant.MSG_ERROR,e));
break;
}
}
}
public void write(byte[]bytes){
try {
//后期会将网络发送和协议解析拆开
mOutStream.write(bytes);
} catch (IOException e) {
e.printStackTrace();
}
}
public void cancel(){
try {
mSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
AcceptThread:
package com.lmj.bluetoothdemo.server;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothServerSocket;
import android.bluetooth.BluetoothSocket;
import android.os.Handler;
import java.io.IOException;
import java.util.UUID;
public class AcceptThread extends Thread{
//连接的名字,
private static final String NAME="";
//uuid,蓝牙通信的基础常量
private static final UUID MY_UUID=UUID.fromString(Constant.CONNECTTION_UUID);
private final BluetoothServerSocket mServerSocket;
private final BluetoothAdapter mBluetoothAdapter;
//和ui通信用的,将事件发送给ui,以为ui是不同的线程,
private final Handler mHandler;
//服务端新建线程,进行创建socket
private ConnectedThread mConnectedThread;
private final String NAME="";
/* public AcceptThread(Object adapter, Handler mUIHandler, BluetoothAdapter mBluetoothAdapter, Handler mHandler) {
this.mBluetoothAdapter = mBluetoothAdapter;
this.mHandler = mHandler;
mServerSocket = null;
}*/
public AcceptThread( BluetoothAdapter mBluetoothAdapter, Handler mHandler) {
this.mBluetoothAdapter = mBluetoothAdapter;
this.mHandler = mHandler;
BluetoothServerSocket tmp=null;
try{
//整么的创建服务器端的socket,调用listenUsingRfcommWithServiceRecord方法创建,(常量,uuid必须是指定的)
//
tmp=mBluetoothAdapter.listenUsingRfcommWithServiceRecord(NAME,MY_UUID);
}catch (IOException E){}
mServerSocket=tmp;
}
public void run(){
BluetoothSocket socket=null;
//监听直到异常或socket重置,
//服务端不退出,要长期开启,所以用while (true){},socket对象出问题的时候,他会退出
while (true){
try{
//收到请求,进入监听
mHandler.sendEmptyMessage(Constant.MSG_START_LISTENING);
//创建socket
socket=mServerSocket.accept();
}catch (IOException e){
mHandler.sendMessage(mHandler.obtainMessage(Constant.MEG_ERROR,e));
break;
}
if (socket!=null){
manageConnectedSocket(socket);
try{
mServerSocket.close();
//到这里面进行管理
mHandler.sendEmptyMessage(Constant.MSG_FINISH_LISTENING);
}catch (IOException e){
e.printStackTrace();
}
break;
}
}
}
private void manageConnectedSocket(BluetoothSocket socket) {
//只支持同时处理一个连接,真实情况下,这里是个连接池,服务端要能处理多个连接,mConnectedThread不为空,就把之前
//客户端踢掉
if (mConnectedThread!=null){
mConnectedThread.cancel();
}
//连接前发一个消息给ui,ui返回一个提示
mHandler.sendEmptyMessage(Constant.MSG_GOT_A_CLINET);
//创建了读取数据的一个线程,传socket,以及和ui通信的mHandler
mConnectedThread=new ConnectedThread(socket,mHandler);
}
public void cancel(){
try{
mServerSocket.close();
mHandler.sendEmptyMessage(Constant.MSG_FINISH_LISTENING);
}catch (IOException e){}
}
public void sendData(byte[] data){
if (mConnectedThread!=null){
mConnectedThread.write(data);
}
}
}
客户端的
DeviceAdapter
package com.lmj.bluetoothdemo.client;
import android.bluetooth.BluetoothDevice;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;
import java.util.List;
public class DeviceAdapter extends BaseAdapter {
private List<BluetoothDevice> mData;
private Context mContext;
public DeviceAdapter(List<BluetoothDevice>data,Context context){
mData=data;
//默认数据为空
mContext=context.getApplicationContext();
}
@Override
public int getCount() {
return 0;
}
@Override
public Object getItem(int i) {
return null;
}
@Override
public long getItemId(int i) {
return 0;
}
@Override
public View getView(int i, View view, ViewGroup viewGroup) {
View itemView=view;
//复用veiw,优化性能
if(itemView==null){
//传下来的view为空,就创建一次,用android自带的简单simple_list_item_2来绘制view
itemView=LayoutInflater.from(mContext).inflate(android.R.layout.simple_list_item_2,viewGroup,false);
}
TextView line1=(TextView)itemView.findViewById(android.R.id.text1);
TextView line2=(TextView)itemView.findViewById(android.R.id.text2);
//获取对应的蓝牙设备
BluetoothDevice device=(BluetoothDevice)getItem(i);
//第一行显示名称
line1.setText(device.getName());
line2.setText(device.getAddress());
//第二行显示地址
return itemView;
}
public void refresh(List<BluetoothDevice>data){
mData=data;
//刷新一次数据,就发一次通知,注册的是观察者模式
notifyDataSetChanged();
}
}
BluetoothController:
package com.lmj.bluetoothdemo.client;
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.Context;
import android.content.Intent;
import java.util.ArrayList;
import java.util.List;
//设置蓝牙被别的设备检查到
public class BluetoothController {
/* 本地蓝牙适配器*/
private BluetoothAdapter mAdapter;
public BluetoothController(){
mAdapter=BluetoothAdapter.getDefaultAdapter();
}
public boolean isSupportBlueTooth() {
if (mAdapter != null) {
//支持蓝牙,一般设备都支持蓝牙
return true;
} else {
return false;
}
}
public boolean getBlueToothStatus(){
//判断蓝牙状态,true为打开,false为关闭
//如果不支持,则会空指针,所以我们在mAdapter里加个断点函数
assert(mAdapter!=null);
return mAdapter.isEnabled();
}
/**
*打开蓝牙
* @param activity
* @param requestCode
*/
//系统主动调,一般不要设置成手动调用
public void turnOnBluetooth(Activity activity,int requestCode){
//通过intent获取蓝牙,action_request_enable请求可用
Intent intent=new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
//知道它的返回结果
activity.startActivityForResult(intent,requestCode);
//设置成自动调用
mAdapter.enable();
}
public void enableVisibly(Context context){
Intent discoverableIntent=new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
//可发生的时间做一个intent。
discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION,300);
//不需要forResult,因为设备不止一个,通过广播来作用
context.startActivity(discoverableIntent);
}
public void findDevice(){
assert(mAdapter!=null);
mAdapter.startDiscovery();
}
/**
* 获取绑定设备
* @return
*/
public List<BluetoothDevice>getBondedDeviceList(){
return new ArrayList<>(mAdapter.getBondedDevices());
}
public void turnOffBlueTooth() {
mAdapter.disable();
}
}
目前就这些,后期会完善好。