首先介绍基本类及方法
一,BlueboothAdapter这个就是表示本机,里面几个常用的方法如下。
1,getDefaultAdapter 这个是静态的方法,通过它可以获取BlueboothAdapter对象
2,enable() 这个方法会弹出一个对话框(包含“确定”,“取消”按钮)提示用户打开蓝牙,用户选择确定则这个方法会返回true,取消返回false.
3,getNmae() 返回本机蓝牙的名称
4,getRemoteDevice(String address)根据给定一个地址参数获取远程蓝牙。
5,getAddress 获取本机的地址
6,startDiscovery() 扫描周围蓝牙,若找到蓝牙会发送 BluetoothDevice.
ACTION_FOUND广播
7 cancelDiscovery() 取消扫描
8,isEnabled() 判断蓝牙是否打开若打开则返回true,没有打开返回false
9,getBondedDevices() 返回绑定的蓝牙,
10,listenUsingRfcommWithServiceReord(String name,UUID uuid) 其中name通常是你的包名,也可以是任意字符串,UUID你可以通过浏览器在线获取
返回的是一个BlueboothServerSocket对象
BlueboothAdapter中常用的方法就是这么多,接下来是BlueboothDevice
二,BlueboothDevice 这个表示远程的设备,常用方法如下
1,getName 获取远程蓝牙的名字
2,getAddress获取远程蓝牙的地址
3,getBondState()获取远程蓝牙的绑定状态,Bond_none 为绑定,bond_bonding正在绑定,bond_bonded已经绑定
3,createBond() 调用这个方法可以进行绑定蓝牙,这个方法要求的最低版本是19,当然你还可以通过反射进行绑定如下
Method method=(Method)BluetoothDevice.class.getMethod("createBond");
method.invoke(device);//device为你想要绑定的远程蓝牙
4,createRfcommSocketToServiceRecord(UUID uuid)//根据uuid获取BlueboothSocket对象,其中uuid一定要跟listenUsingRfcommWithServiceReord中给定的uuid一致
这里再说明一定蓝牙客户端与服务端进行通信时用BlueboothSocket获取输入流,输出流来进行通信的。
下面是代码包含蓝牙的搜索及绑定
public class MainActivity extends AppCompatActivity implements View.OnClickListener, AdapterView.OnItemClickListener { private Button search; private Button client; private ListView listBluebooth; private BluetoothAdapter bAdapter; private BluetoothDevice bDevice; private ListAdapter listAdapter; private List<String> deviceNames = new ArrayList<>(); private List<String> deviceAddress = new ArrayList<>(); private BluetoothDevice device; private IsSuccess isSuccess; private String isServer = "on";//判断是否为服务端 private Handler handler = new Handler() { @Override public void handleMessage(Message msg) { search.setText("搜索完成"); client.setText("搜索完成"); } }; private boolean sureBlueboothIsOpen=true;//默认蓝牙是打开状态 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); init(); } private void init() { client = (Button) findViewById(R.id.client); client.setOnClickListener(this); search = (Button) findViewById(R.id.search); search.setOnClickListener(this); listBluebooth = (ListView) findViewById(R.id.list_bluebooth); IntentFilter filter = new IntentFilter(); filter.addAction(BluetoothDevice.ACTION_FOUND); filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED); registerReceiver(receiver, filter); bAdapter = BluetoothAdapter.getDefaultAdapter(); } //得到已绑定的设备 private void addBoundDevice(BluetoothAdapter bAdapter) { Set<BluetoothDevice> set = bAdapter.getBondedDevices(); Log.d("test", "set:" + set.size()); for (BluetoothDevice device : set) { deviceNames.add(device.getName()); deviceAddress.add(device.getAddress()); } listAdapter = new ListAdapter(MainActivity.this, R.layout.bluebooth_item, deviceNames); /*listAdapter.notifyDataSetChanged();*/ listBluebooth.setAdapter(listAdapter); listBluebooth.setOnItemClickListener(this); } //搜索到发现蓝牙广播 BroadcastReceiver receiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { Log.d("test", "action:" + intent.getAction()); if (intent.getAction().equals(BluetoothDevice.ACTION_FOUND)) { bDevice = (BluetoothDevice) intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); if (bDevice.getBondState() == BluetoothDevice.BOND_NONE) { Log.d("test", "none"); deviceNames.add(bDevice.getName()); deviceAddress.add(bDevice.getAddress()); } listAdapter.notifyDataSetChanged(); listBluebooth.setAdapter(listAdapter); } else if (intent.getAction().equals(BluetoothAdapter.ACTION_DISCOVERY_FINISHED)) { handler.sendEmptyMessage(1); } } }; @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (resultCode == RESULT_OK) { Log.d("test", "result ok"); }else { Log.d("test", resultCode + " result"); } super.onActivityResult(requestCode, resultCode, data); } @Override public void onClick(View v) { switch (v.getId()) { //服务端只需打开蓝牙,不需扫描,只要等待客户端接入即可 case R.id.search: if (!bAdapter.isEnabled()) { sureBlueboothIsOpen=bAdapter.enable(); } if (sureBlueboothIsOpen) { isServer = "yes"; Intent intent1 = new Intent(MainActivity.this, ChatActivity.class); intent1.putExtra("is_server", isServer); startActivity(intent1); client.setEnabled(false); }else { Toast.makeText(getApplicationContext(),"蓝牙没有开启",Toast.LENGTH_SHORT).show(); return; } break; case R.id.client: addBoundDevice(bAdapter); //用户按下取消按钮返回false,确定返回true if (!bAdapter.isEnabled()) { sureBlueboothIsOpen=bAdapter.enable(); } if (sureBlueboothIsOpen) { isServer = "no"; bAdapter.startDiscovery(); client.setText("搜索蓝牙中"); isSuccess = new IsSuccess(); isSuccess.start(); search.setEnabled(false); }else { Toast.makeText(getApplicationContext(),"蓝牙没有开启",Toast.LENGTH_SHORT).show(); return; } break; } } @Override protected void onDestroy() { super.onDestroy(); unregisterReceiver(receiver); if (isSuccess != null) isSuccess.interrupt(); } //deviceNmaes list子项的点击事件配对蓝牙 @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { //你要想绑定的蓝牙 device = bAdapter.getRemoteDevice(deviceAddress.get(position)); try { Method method = (Method) BluetoothDevice.class.getMethod("createBond"); Log.d("test", (boolean) method.invoke(device) + ":" + device.getBondState()); /*Log.d("test", device.createBond() + ":" + device.getBondState());*/ } catch (Exception e) { e.printStackTrace(); } /* address = deviceAddress.get(position); Intent intent1 = new Intent(MainActivity.this, ChatActivity.class); intent1.putExtra("device", address); intent1.putExtra("is_server", isServer); startActivity(intent1);*/ } //根据bDevice绑定状态判断用户是否按下匹配按钮 //这个线程会一直执行下去直到用户绑定蓝牙成功 class IsSuccess extends Thread { private int i = 0; @Override public void run() { while (true) { i++; /*Log.d("test", "device state:" + bDevice.getBondState());*/ if (device != null) { break; } /* if (bDevice.getBondState() == 12 ) { break; }*/ try { sleep(1000); } catch (Exception e) { e.printStackTrace(); } } runOnUiThread(new Runnable() { @Override public void run() { if (device.getBondState() == 12) { Intent intent1 = new Intent(MainActivity.this, ChatActivity.class); intent1.putExtra("device", device.getAddress()); intent1.putExtra("is_server", isServer); startActivity(intent1); } } }); } } }
接着是客户端与服务端通信的代码
public class ChatActivity extends Activity implements View.OnClickListener { private ListView chat; private EditText content; private static String UUID_CODE="42385BC1-F486-5196-1956-9CBEF428212B"; private Button send; private BluetoothSocket socket; private BluetoothServerSocket serverSocket; private BluetoothAdapter bAdapter; private BluetoothDevice device; private ReadThread readThread;//读线程 private String isServer; private List<String> messageLists = new ArrayList<>(); private ArrayAdapter arrayAdapter; private Handler handler = new Handler() { @Override public void handleMessage(Message msg) { if (msg.what == 3) { Log.d("test", "message ==3"); readThread = new ReadThread(socket); readThread.start(); messageLists.add("已连接到服务端:" + socket.getRemoteDevice().getName()); } arrayAdapter = new ArrayAdapter(ChatActivity.this, android.R.layout.simple_list_item_1, messageLists); switch (msg.what) { case 1: break; case 2: String content = (String) msg.obj; Log.d("test", "handler:" + content); messageLists.add(content); break; } Log.d("test", messageLists.size() + ""); arrayAdapter.notifyDataSetChanged(); chat.setAdapter(arrayAdapter); chat.setSelection(messageLists.size()-1); } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.char_layout); init(); } @Override protected void onStart() { super.onStart(); String isServer = getIntent().getStringExtra("is_server"); if (isServer.equals("yes")) { Log.d("test", "server"); this.isServer = "server"; ServerThread serverThread = new ServerThread(bAdapter); serverThread.start(); } else if (isServer.equals("no")) { Log.d("test", "client"); this.isServer = "client"; ClientThread clientThread = new ClientThread(device); clientThread.start(); } } private void init() { chat = (ListView) findViewById(R.id.chat); content = (EditText) findViewById(R.id.content); send = (Button) findViewById(R.id.send); send.setOnClickListener(this); bAdapter = BluetoothAdapter.getDefaultAdapter(); String address = getIntent().getStringExtra("device"); if (!TextUtils.isEmpty(address)) { Log.d("test", "chat adress:" + address); device = bAdapter.getRemoteDevice(address); } } @Override public void onClick(View v) { switch (v.getId()) { case R.id.send: Log.d("test", "onclick"); if (!TextUtils.isEmpty(content.getText())) { /*sendMessage();*/ Log.d("test", "sendmessage"); sendMessage(content.getEditableText().toString()); //若读线程为空则再次创建读线程 if (readThread == null) { readThread = new ReadThread(socket); readThread.start(); Log.d("test", "readThread==nulll"); }else { Log.d("test", "readThread!=null"); } } break; } } //发送信息 //客户端 private class ClientThread extends Thread { private BluetoothDevice device; public ClientThread(BluetoothDevice device) { this.device = device; } @Override public void run() { try { Log.d("test", "client"); bAdapter.cancelDiscovery(); socket = device.createRfcommSocketToServiceRecord(UUID.fromString(UUID_CODE)); Log.d("test", device.getUuids().toString()); socket.connect();
//通过BlueboothSocket的getRemoteDevice()来确认连接的远程蓝牙是否是自己想要连接的 Log.d("test", "client connet success:"+socket.getClass().toString() + socket.getRemoteDevice().getName() + ":" + socket.getRemoteDevice().getAddress()); /*if (socket != null) { readThread = new ReadThread(socket); readThread.start(); }*/ Log.d("test", "start client read"); //这里创建的readThread为空 /*readThread = new ReadThread(socket); readThread.start();*/ Message message=new Message(); message.what=3; handler.sendMessage(message); } catch (Exception e) { e.printStackTrace(); runOnUiThread(new Runnable() { @Override public void run() { if (socket != null) { } });} } } //服务端 private class ServerThread extends Thread { private BluetoothAdapter adapter; public ServerThread(BluetoothAdapter adapter) { this.adapter = adapter; } @Override public void run() { try { Log.d("test", "serverThread"); /*bAdapter.cancelDiscovery();*/ serverSocket = adapter.listenUsingInsecureRfcommWithServiceRecord("bluetoothdemo", UUID.fromString(UUID_CODE)); socket = serverSocket.accept(); Log.d("test", "server connect success"); } catch (Exception e) { } runOnUiThread(new Runnable() { @Override public void run() { Log.d("test", "start server read"); if (socket != null) { // readThread = new ReadThread(socket); readThread.start(); messageLists.add("客户端:" + socket.getRemoteDevice().getName() + "已连接"); Message message=new Message(); message.what=1; handler.sendMessage(message); /* sendMessage("client:"+socket.getRemoteDevice().getName()+"已经连接");*///自己会读取自己这边放入的字符 /* socket.close();*/ } } }); } } //从输入流中读取,因为read(byte [])这个方法会阻塞,所以要放到子线程中 private class ReadThread extends Thread { private BluetoothSocket socket; private InputStream stream; public ReadThread(BluetoothSocket socket) { this.socket = socket; } @Override public void run() { super.run(); while (true) { try { stream = socket.getInputStream(); /*if (stream != null) *//*Log.d("test", "stram not null");*//* else Log.d("test", "stram null");*/ byte[] buff = new byte[1024]; stream.read(buff); String content=new String(buff); //判断是是服务端还是客户端 if (isServer.equals("server")) { content="客户端:"+content; }else { content="服务端:"+content; } Message message = new Message(); message.obj = content; message.what = 2; handler.sendMessage(message); } catch (Exception e) { e.printStackTrace(); } } } } //发送信息 private void sendMessage(String content) { if (socket != null) { Log.d("test", "socket class:" + socket.getRemoteDevice().getName() + ":" + socket.getRemoteDevice().getAddress()); Log.d("test", "socket class:" + socket.toString()); try { Log.d("test", "sock not null"); OutputStream outputStream = socket.getOutputStream(); ; if (outputStream != null) { Log.d("test", "output not null"); }else { Log.d("test", "output null"); } outputStream.write(content.getBytes()); messageLists.add(content); /* InputStream stream = socket.getInputStream(); byte[] buff = new byte[1024]; stream.read(buff); String s = new String(buff); Log.d("test", "read:" + s);*/ Log.d("test", "tttt"); Message message1 = new Message(); message1.what = 1; handler.sendMessage(message1); } catch (Exception e) { e.printStackTrace(); } } else { Log.d("test", "socket null"); } } @Override protected void onDestroy() { super.onDestroy(); if (readThread != null) { readThread.interrupt(); } } }
这里有几个坑想说一下,当你从输入流中读取信息的时候一定要保证读线程是不为空的,不然一定读取不到信息,所以我在按下发送按钮的时候再重新检查下读线程是否为空
要是为空则重新创建一个读线程