目标:实现简单的蓝牙聊天功能(基于经典蓝牙)
参考官方API
关键类:BluetoothAdapter,BluetoothDevice,BluetoothServerSocket,BluetoothSocket
详细步骤
1.初始化蓝牙
关键类:BluetoothAdapter
通过BluetoothAdapter判断是否支持蓝牙,蓝牙的开启关闭状态
bleAdapter = BluetoothAdapter.getDefaultAdapter(); if (bleAdapter == null) { Toast.makeText(this, "不支持蓝牙", Toast.LENGTH_SHORT).show(); return; } if (!bleAdapter.isEnabled()) {//蓝牙未开启 startActivity(new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE)); }
2.搜索附近蓝牙
if (!bleAdapter.isDiscovering()) bleAdapter.startDiscovery();
搜索后返回的结果(BluetoothDevice)以广播的形式发送过来,所以必须针对 ACTION_FOUND
Intent 注册一个 BroadcastReceiver
private final BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { if (BluetoothDevice.ACTION_FOUND.equals(intent.getAction())) { BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); list.add(device); adapter.notifyDataSetChanged(); // Log.e("bluetoothDevice:", device.getName() + "," + device.getAddress()); } } };
IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND); registerReceiver(mReceiver, filter);
3.连接(连接为服务端(等待被连接),客户端连接(主动去连接))
关键类:BluetoothServerSocket,BluetoothSocket.
连接为服务端:等待被连接是一个线程阻塞的过程,所以需要在子线程中做处理。
// 等待被连接 private class AcceptThread extends Thread { private final BluetoothServerSocket mServerSocket; public AcceptThread() { BluetoothServerSocket tem = null; try { tem = bleAdapter.listenUsingRfcommWithServiceRecord(NAME, UUID.fromString(MY_UUID)); } catch (IOException e) { e.printStackTrace(); } mServerSocket = tem; } @Override public void run() { BluetoothSocket bluetoothSocket = null; try { bluetoothSocket = mServerSocket.accept();//等待客户端的连接,线程阻塞。 // connectedThread = new ConnectedThread(bluetoothSocket); // connectedThread.start(); System.out.println("sunjinglunAccept:" + bluetoothSocket.isConnected()); mServerSocket.close(); } catch (Exception e) { e.printStackTrace(); } } }连接为客户端:
private class ConnectServiceThread extends Thread { private BluetoothDevice device; public ConnectServiceThread(BluetoothDevice device) { this.device = device; } @Override public void run() { try { bleAdapter.cancelDiscovery();//连接前先取消搜索 BluetoothSocket socket = device.createRfcommSocketToServiceRecord(UUID.fromString(MY_UUID)); socket.connect();//请求连接 // connectedThread = new ConnectedThread(socket); // connectedThread.start(); System.out.println("sunjinglunConnect:" + socket.isConnected()); } catch (IOException e) { e.printStackTrace(); } } }
4.收发数据
关键类:BluetoothSocket,InputStream,OutputStream.
private class ConnectedThread extends Thread { private final BluetoothSocket msocket; private final InputStream mInputStream; private final OutputStream mOutputStream; public ConnectedThread(BluetoothSocket socket) { msocket = socket; InputStream inputStream = null; OutputStream outputStream = null; try { inputStream = msocket.getInputStream(); outputStream = msocket.getOutputStream(); } catch (IOException e) { e.printStackTrace(); } mInputStream = inputStream; mOutputStream = outputStream; } @Override public void run() { byte[] buffer = new byte[1024]; int bytes; while (true) { try { bytes = mInputStream.read(buffer); System.out.println(new String(buffer, 0, bytes)); Message message = handler.obtainMessage(); message.obj = new String(buffer, 0, bytes); handler.sendMessage(message); } catch (Exception e) { break; } } } public void write(byte[] bytes) { try { // System.out.println("wo:" + ); ShowMessage(new String(bytes)); mOutputStream.write(bytes); } catch (IOException e) { e.printStackTrace(); } } }
*****************************附上完整代码*****************************
package com.my.self.notepad.blue_tooth; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothServerSocket; import android.bluetooth.BluetoothSocket; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.Toast; import com.my.self.notepad.R; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; import java.util.List; import java.util.UUID; public class BluetoothActivity extends AppCompatActivity implements OnRecyclerViewItemClickListener { private BluetoothAdapter bleAdapter; private final String MY_UUID = "2a4e5cff-d6f1-4118-ba8d-88d65b0a4e8e"; private final String NAME = "sjl"; //列表信息 private RecyclerView rvDevices; private List<BluetoothDevice> list; private BluetoothDevicesAdapter adapter; //聊天信息 private RecyclerView reChat; private ChatAdapter chatAdapter; private List<String> stringList; private ConnectedThread connectedThread; // private EditText etMessage; private Button btnSendmsg; // private Handler handler = new Handler() { @Override public void handleMessage(Message msg) { super.handleMessage(msg); ShowMessage((String) msg.obj); } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_bluetooth); initView(); initData(); initBluetooth(); new AcceptThread().start();//挂起为服务端连接(等待客户端的连接) } protected void initView() { rvDevices = (RecyclerView) findViewById(R.id.rv_devices); etMessage = (EditText) findViewById(R.id.et_message); btnSendmsg = (Button) findViewById(R.id.btn_sendmsg); reChat = (RecyclerView) findViewById(R.id.rv_cat); } protected void initData() { list = new ArrayList<>(); adapter = new BluetoothDevicesAdapter(list); rvDevices.setLayoutManager(new LinearLayoutManager(this)); rvDevices.setAdapter(adapter); adapter.setOnItemClickListener(this); stringList = new ArrayList<>(); chatAdapter = new ChatAdapter(stringList); reChat.setLayoutManager(new LinearLayoutManager(this)); reChat.setAdapter(chatAdapter); } protected void initBluetooth() { bleAdapter = BluetoothAdapter.getDefaultAdapter(); if (bleAdapter == null) { Toast.makeText(this, "不支持蓝牙", Toast.LENGTH_SHORT).show(); return; } if (!bleAdapter.isEnabled()) {//蓝牙未开启 startActivity(new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE)); } IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND); registerReceiver(mReceiver, filter); startSearch(); } //发送消息 public void onClick(View view) { connectedThread.write(MeeageMachin(etMessage.getText().toString())); } //消息处理(发送前先拼上蓝牙名称) public byte[] MeeageMachin(String message) { String msg = bleAdapter.getName() + ":" + message; return msg.getBytes(); } //开始搜索 protected void startSearch() { if (!bleAdapter.isDiscovering()) bleAdapter.startDiscovery(); } @Override public void onItemClick(View view, int position) { BluetoothDevice device = list.get(position); Log.e("sunjinglun", device.getName() + "," + device.getAddress()); bleAdapter.cancelDiscovery(); // new ConnectServiceThread(device, MY_UUID).start(); new ConnectServiceThread(device).start();//点击连接到服务端 } //搜索蓝牙的结果 private final BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { if (BluetoothDevice.ACTION_FOUND.equals(intent.getAction())) { BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); list.add(device); adapter.notifyDataSetChanged(); // Log.e("bluetoothDevice:", device.getName() + "," + device.getAddress()); } } }; @Override protected void onDestroy() { super.onDestroy(); unregisterReceiver(mReceiver); } // 为服务端连接(等待被客户端连接) private class AcceptThread extends Thread { private final BluetoothServerSocket mServerSocket; public AcceptThread() { BluetoothServerSocket tem = null; try { tem = bleAdapter.listenUsingRfcommWithServiceRecord(NAME, UUID.fromString(MY_UUID)); } catch (IOException e) { e.printStackTrace(); } mServerSocket = tem; } @Override public void run() { BluetoothSocket bluetoothSocket = null; try { bluetoothSocket = mServerSocket.accept();//等待客户端的连接,线程阻塞。 connectedThread = new ConnectedThread(bluetoothSocket); connectedThread.start();//连接成果后开启消息接收,接受客户端发送过来的消息 System.out.println("sunjinglunAccept:" + bluetoothSocket.isConnected()); mServerSocket.close(); } catch (Exception e) { e.printStackTrace(); } } } //为客户端连接(连接到服务端) private class ConnectServiceThread extends Thread { private BluetoothDevice device; public ConnectServiceThread(BluetoothDevice device) { this.device = device; } @Override public void run() { try { bleAdapter.cancelDiscovery();//连接前先取消搜索 BluetoothSocket socket = device.createRfcommSocketToServiceRecord(UUID.fromString(MY_UUID)); socket.connect();//请求连接 connectedThread = new ConnectedThread(socket); connectedThread.start();//连接成果后开启消息接收,接受服务端发送过来的消息 System.out.println("Connect:" + socket.isConnected()); } catch (IOException e) { e.printStackTrace(); } } } //收发消息, private class ConnectedThread extends Thread { private final BluetoothSocket msocket; private final InputStream mInputStream; private final OutputStream mOutputStream; public ConnectedThread(BluetoothSocket socket) { msocket = socket; InputStream inputStream = null; OutputStream outputStream = null; try { inputStream = msocket.getInputStream(); outputStream = msocket.getOutputStream(); } catch (IOException e) { e.printStackTrace(); } mInputStream = inputStream; mOutputStream = outputStream; } @Override public void run() { byte[] buffer = new byte[1024]; int bytes; while (true) { try { bytes = mInputStream.read(buffer); System.out.println(new String(buffer, 0, bytes)); Message message = handler.obtainMessage(); message.obj = new String(buffer, 0, bytes); handler.sendMessage(message); } catch (Exception e) { break; } } } public void write(byte[] bytes) { try { // System.out.println("wo:" + ); ShowMessage(new String(bytes)); mOutputStream.write(bytes); } catch (IOException e) { e.printStackTrace(); } } } //显示消息 public void ShowMessage(String message) { stringList.add(message); chatAdapter.notifyItemChanged(stringList.size() - 1); } }
最后不要忘记申请蓝牙权限。