蓝牙Socket通讯
前段時間寫了藍牙gatt協議的通訊,發現Android開發藍牙,與硬件通訊使用gatt協議。如果個Android設備之間開發藍牙通訊該怎么寫。就在查了有關方面的資料,了解了Socket通訊,今天就寫下Android設備之間的藍牙Socket通訊。
首先你得有兩部Android設備,一個作為服務器,一個作為客戶端。我把服務器與客戶端的代碼都寫在同一個工程中,只需要選擇當前設備是作為服務器,還是客戶端就OK.
首先看下主界面的代碼,用于選擇服務器或客戶端的。
public class MainActivity extends AppCompatActivity {private Button mServerButton, mClientButton; @Override protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initView(); mClientButton.setOnClickListener(v -> {Intent intent = new Intent(MainActivity.this, ClientActivity.class); startActivity(intent); }); mServerButton.setOnClickListener(v -> {Intent intent = new Intent(MainActivity.this, ServerActivity.class); startActivity(intent); }); }private void initView() {mServerButton = findViewById(R.id.btn_server); mClientButton = findViewById(R.id.btn_client); } }很明顯主界面有兩個按鈕,用于選擇服務器或客戶端。
我們先看下服務器的創建。
public class ServerActivity extends AppCompatActivity {private ListView mReceiveListView, mSendListView; private Button mSendButton, mSearchButton; private EditText mSendEditText; private BluetoothServer bluetoothServer; /** * 用于存放接收到的數據 */ private List<String> stringList = new ArrayList<>(); /** * 用于存放歷史數據 */ private List<String> strings = new ArrayList<>(); private TimerTask timerTask = new TimerTask() {@Override public void run() {stringList = bluetoothServer.getMeg(); runOnUiThread(() -> {ArrayAdapter arrayAdapter = new ArrayAdapter(ServerActivity.this, R.layout.support_simple_spinner_dropdown_item, stringList); mReceiveListView.setAdapter(arrayAdapter); }); }}; @Override protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState); setContentView(R.layout.activity_client); initView(); mSearchButton.setVisibility(View.GONE); bluetoothServer = new BluetoothServer(ServerActivity.this); bluetoothServer.start(); Timer timer = new Timer(); timer.schedule(timerTask, 0, 1000); mSendButton.setOnClickListener(v -> {bluetoothServer.sendData(mSendEditText.getText().toString()); strings.add(mSendEditText.getText().toString()); ArrayAdapter arrayAdapter = new ArrayAdapter(ServerActivity.this, R.layout.support_simple_spinner_dropdown_item, strings); mSendListView.setAdapter(arrayAdapter); }); }private void initView() {mReceiveListView = findViewById(R.id.receive_list); mSendListView = findViewById(R.id.send_list); mSendButton = findViewById(R.id.btn_send); mSearchButton = findViewById(R.id.btn_search); mSendEditText = findViewById(R.id.send_et); } }服務器界面的工作主要有兩個:
一:創建服務器。
bluetoothServer.start();服務器如何創建需要重點看看start()里面的寫法,稍后在藍牙服務類里面有詳解.
二:不斷的接收客戶端發送過來的數據及向客戶端發送數據
private TimerTask timerTask = new TimerTask() {@Override public void run() {stringList = bluetoothServer.getMeg(); runOnUiThread(() -> {ArrayAdapter arrayAdapter = new ArrayAdapter(ServerActivity.this, R.layout.support_simple_spinner_dropdown_item, stringList); mReceiveListView.setAdapter(arrayAdapter); }); }}; Timer timer = new Timer(); timer.schedule(timerTask, 0, 1000);這個定時器就是用于接收客戶端發過來的數據。
向客戶端發送數據就很簡單,在藍牙服務類里面的sendData()方法里面。
藍牙服務界面的寫法就這樣,接著看看藍牙客戶端的寫法:
public class ClientActivity extends AppCompatActivity {private ListView mReceiveListView, mSendListView; private Button mSendButton, mSearchButton; private EditText mSendEditText; /** * * 存放藍牙設備列表 */ private List<BluetoothDevice> bluetoothDevices = new ArrayList<>(); /** * 存放歷史消息記錄 */ private List<String> strings = new ArrayList<>(); /** * 存放接收到的消息 */ private List<String> listMsg = new ArrayList<>(); /** * 顯示接收消息的定時器 */ private TimerTask timerTask = new TimerTask() {@Override public void run() {listMsg = mBluetoothClient.getMsg(); runOnUiThread(() -> {ArrayAdapter arrayAdapter = new ArrayAdapter(ClientActivity.this, R.layout.support_simple_spinner_dropdown_item, listMsg); mReceiveListView.setAdapter(arrayAdapter); }); }}; /** * 藍牙客戶端 */ private BluetoothClient mBluetoothClient; @Override protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState); setContentView(R.layout.activity_client); mBluetoothClient = new BluetoothClient(ClientActivity.this); initView(); listener(); Timer timer = new Timer(); timer.schedule(timerTask, 0, 1000); }private void initView() {mReceiveListView = findViewById(R.id.receive_list); mSendListView = findViewById(R.id.send_list); mSendButton = findViewById(R.id.btn_send); mSearchButton = findViewById(R.id.btn_search); mSendEditText = findViewById(R.id.send_et); }private void listener() {mSearchButton.setOnClickListener(v -> {mBluetoothClient.searchBluetooth(); }); mSendButton.setOnClickListener(v -> {mBluetoothClient.sendData(mSendEditText.getText().toString()); strings.add(mSendEditText.getText().toString()); ArrayAdapter arrayAdapter = new ArrayAdapter(ClientActivity.this, R.layout.support_simple_spinner_dropdown_item, strings); mSendListView.setAdapter(arrayAdapter); }); }@Override protected void onResume() {super.onResume(); IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED); intentFilter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED); intentFilter.addAction(BluetoothDevice.ACTION_FOUND); registerReceiver(receiver, intentFilter); }@Override protected void onPause() {super.onPause(); unregisterReceiver(receiver); }/** * 注冊藍牙搜索廣播 */ private BroadcastReceiver receiver = new BroadcastReceiver() {@Override public void onReceive(Context context, Intent intent) {String action = intent.getAction(); switch (action) {case BluetoothAdapter.ACTION_DISCOVERY_STARTED:mSearchButton.setText("正在搜索"); break; case BluetoothAdapter.ACTION_DISCOVERY_FINISHED:mSearchButton.setText("搜索"); AlertDialog.Builder builder = new AlertDialog.Builder(ClientActivity.this); builder.setTitle("藍牙搜索"); View view = View.inflate(ClientActivity.this, R.layout.activity_bluetoothdevice_listview, null); builder.setView(view); ListView mListView = view.findViewById(R.id.bluetooth_device); BluetoothDeviceAdapter mBluetoothDeviceAdapter = new BluetoothDeviceAdapter(bluetoothDevices, ClientActivity.this); mListView.setAdapter(mBluetoothDeviceAdapter); builder.show(); mListView.setOnItemClickListener((parent, view1, position, id) -> {BluetoothDevice device = (BluetoothDevice) mBluetoothDeviceAdapter.getItem(position); mBluetoothClient.connect(device); }); break; case BluetoothDevice.ACTION_FOUND:BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); if (!bluetoothDevices.contains(device)) {bluetoothDevices.add(device); }break; default:break; }}}; }客戶端的主要工作就是搜索藍牙及連接藍牙。在客戶端也開了一個定時器,它的作用與服務器的定時器一樣用于接收數據 ,接收服務器發送過來的數據 。
藍牙的搜索及連接主要看看注冊的廣播。如有不懂得,可以去查下如何通過注冊廣播搜索藍牙設備。
接著我們看看藍牙服務類及藍牙客戶類的寫法及作用。
一:藍牙服務類。
這個類涉及到藍牙服務器的創建及客戶端與服務器的連接。先看下代碼:
public class BluetoothServer {private Context context; /** * 創建服務器的名稱 */ private String name = "FIUBluetoothServer"; /** * 創建服務器所用的id */ public static final UUID MY_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"); /** * 創建線程池 */ private ExecutorService mExecutorService = Executors.newCachedThreadPool(); /** * 藍牙檢測類 */ private BluetoothUtils mBluetoothUtils = new BluetoothUtils(); /** * 藍牙服務Socket */ private BluetoothServerSocket mBluetoothServerSocket; /** * 藍牙客戶端Socket */ private BluetoothSocket mBluetoothSocket; /** * 藍牙服務器是否正在工作 */ private boolean isWorking; /** * 存放從客戶端讀取到的數據 */ private List<String> stringList = new ArrayList<>(); public BluetoothServer(Context context) {this.context = context; }/** * 創建服務器,并連接客戶端 */ public void start() {listener(); }/** * 創建服務器監聽 */ private void listener() {mExecutorService.execute(() -> {if (mBluetoothUtils.existBluetooth()) {if (mBluetoothUtils.openBluetooth()) {if (mBluetoothServerSocket == null) {try {mBluetoothServerSocket = BluetoothAdapter.getDefaultAdapter().listenUsingRfcommWithServiceRecord(name, MY_UUID); } catch (IOException e) {e.printStackTrace(); }}isWorking = true; try {mBluetoothSocket = mBluetoothServerSocket.accept(); handler.sendEmptyMessage(1); readData(); } catch (IOException e) {e.printStackTrace(); }}} else {Toast.makeText(context, "該設備不支持藍牙", Toast.LENGTH_LONG).show(); }}); }/** * 讀取數據 */ private void readData() {mExecutorService.execute(() -> {try {InputStream inputStream = mBluetoothSocket.getInputStream(); byte[] buffer = new byte[1024]; while (isWorking) {int read = inputStream.read(buffer); if (read != -1) {StringBuilder stringBuilder = new StringBuilder(); if (read < buffer.length) {String s = new String(buffer, 0, read); stringBuilder.append(s); }synchronized (stringList) {stringList.add("客戶端發送"+stringBuilder.toString()); }}}mBluetoothSocket.close(); } catch (IOException e) {e.printStackTrace(); }}); }public List<String> getMeg() {return stringList; }/** * 發送數據 * @param msg */ public void sendData(String msg) {try {byte[] b = msg.getBytes(); mBluetoothSocket.getOutputStream().write(b); mBluetoothSocket.getOutputStream().flush(); } catch (IOException e) {e.printStackTrace(); }}private Handler handler = new Handler(msg -> {switch (msg.what) {case 1:Toast.makeText(context, "客戶端已連接" +mBluetoothSocket.getRemoteDevice().getName(), Toast.LENGTH_LONG).show(); break; default:break; }return false; });在這個類里面創建的變量及方法我都有寫注釋。看注釋應該能明白大致作用.
public void start() {listener(); }start()方法在前面講過,這個方法是創建藍牙服務器的主要方法,在這個方法里面有一個listener()的方法。listener()方法是創建服務器的監聽方法。在這個方法里面有一行代碼:
mBluetoothServerSocket = BluetoothAdapter.getDefaultAdapter().listenUsingRfcommWithServiceRecord(name, MY_UUID);這行代碼就是創建服務器的主要代碼。就靠它創建服務器。name是創建的服務器名稱,MY_UUID是創建服務器的唯一識別id。
我上面寫的id是可以用的。
關羽readData()與sendData()兩個方法里面的數據讀取與寫入都是依靠流操作完成的。有不懂的可以去學習下有關流的知識。在這個類里面服務器的創建及數據的讀取、寫入最為關鍵。這兩大點學會就ok了。
藍牙服務類看完了,我們再來看看藍牙客戶端的藍牙類怎么寫。
public class BluetoothClient {private Context context; private BluetoothUtils mBluetoothUtils = new BluetoothUtils(); private BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); /** * 客戶端Socket */ private BluetoothSocket mBluetoothSocket; /** * 連接服務器的uuid */ public final UUID uuid = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"); /** * 數據輸入輸出流 */ private OutputStream outputStream; private InputStream inputStream; /** * 存放讀取到的數據 */ private List<String> strings = new ArrayList<>(); private StringBuilder stringBuilder = new StringBuilder(); /** * 是否正在工作 */ private boolean isWorking; private ExecutorService mExecutorService; public BluetoothClient(Context context) {this.context = context; mExecutorService = Executors.newCachedThreadPool(); }public void searchBluetooth() {if (mBluetoothUtils.existBluetooth()) {if (mBluetoothUtils.openBluetooth()) {if (mBluetoothAdapter.isDiscovering()) {mBluetoothAdapter.cancelDiscovery(); }mBluetoothAdapter.startDiscovery(); }} else {Toast.makeText(context, "藍牙不被支持使用", Toast.LENGTH_LONG).show(); }}public void connect(BluetoothDevice bluetoothDevice) {mExecutorService.execute(() -> {try {mBluetoothSocket = bluetoothDevice.createInsecureRfcommSocketToServiceRecord(uuid); mBluetoothSocket.connect(); isWorking = true; outputStream = mBluetoothSocket.getOutputStream(); inputStream = mBluetoothSocket.getInputStream(); readData(); } catch (IOException e) {e.printStackTrace(); }}); }public void sendData(String msg) {mExecutorService.execute(() -> {if (mBluetoothSocket != null) {if (outputStream != null) {byte[] bytes = msg.getBytes(); try {outputStream.write(bytes); outputStream.flush(); } catch (IOException e) {e.printStackTrace(); }}}}); }/** * strings * * @return */ public List<String> getMsg() {synchronized (strings) {return strings; }}public void readData() {mExecutorService.execute(() -> {byte[] buffer = new byte[1024 * 2]; while (isWorking) {try {int read = inputStream.read(buffer); if (read != -1) {stringBuilder.delete(0, stringBuilder.length()); if (read < buffer.length) {String s = new String(buffer, 0, read); stringBuilder.append(s); }synchronized (strings) {strings.add("服務器發送" + stringBuilder.toString()); }}} catch (IOException e) {e.printStackTrace(); }}try {mBluetoothSocket.close(); } catch (IOException e) {e.printStackTrace(); }}); } }在前面說過藍牙客戶端主要負責藍牙的搜索及連接。看上面代碼是不是很容易就能發現搜索部分及連接部分。就在searchBluetooth()與connnect()這連個方法里面。這兩個方法搞清楚了,其他的是不是和藍牙服務類基本一樣。
總結
以上是生活随笔為你收集整理的蓝牙Socket通讯的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: fedora linux搜狗输入法,Gi
- 下一篇: c语言 圆周率10000位,圆周率(小数