編輯:關於Android編程
想使用藍牙呢,首先得看手機是否支持,有些低配手機,可能就沒有內置藍牙模塊。當然,一般都會有,我們可以得到唯一的藍牙適配器,進行其他操作。
bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
/** * 開啟藍牙 * * @param activity 上下文 * @return 是否開啟成功 */ public static boolean openBluetooth(Activity activity) { //確認開啟藍牙 if (!getInstance().isEnabled()) { //=默認120秒============================================================== //使藍牙設備可見,方便配對 //Intent in = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE); //in.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300); //activity.startActivityForResult(in,Activity.RESULT_OK); //=1============================================================= //請求用戶開啟,需要提示 //Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); //startActivityForResult(intent, RESULT_FIRST_USER); //=2============================================================= //程序直接開啟,不經過提示 getInstance().enable(); } //T.showLong(context, "已經開啟藍牙"); return getInstance().isEnabled(); } //關閉藍牙 public static boolean closeBluetooth() { return getInstance().disable(); } /** * 掃描已經配對的設備 * * @return */ public static ArrayListscanPairs() { ArrayList list = null; Set deviceSet = getInstance().getBondedDevices(); if (deviceSet.size() > 0) { //存在已經配對過的藍牙設備 list = new ArrayList<>(); list.addAll(deviceSet); } return list; } //開始掃描 public static void scan() { getInstance().startDiscovery(); } //取消掃描 public static void cancelScan() { if (getInstance().isDiscovering()) getInstance().cancelDiscovery(); } //藍牙配對 @TargetApi(Build.VERSION_CODES.KITKAT) public static boolean createBond(BluetoothDevice device) { return bond(device, "createBond"); /*if (device.createBond()) { return device.setPairingConfirmation(true); } return false;*/ } //解除配對 public static boolean removeBond(BluetoothDevice device) { return bond(device, "removeBond"); } @TargetApi(Build.VERSION_CODES.KITKAT) private static boolean bond(BluetoothDevice device, String methodName) { Boolean returnValue = false; if (device != null && device.getBondState() == BluetoothDevice.BOND_NONE) { try { device.setPairingConfirmation(false); cancelPairingUserInput(device); Method removeBondMethod = BluetoothDevice.class.getMethod(methodName); returnValue = (Boolean) removeBondMethod.invoke(device); } catch (Exception e) { e.printStackTrace(); } } return returnValue; } //取消配對 public static boolean cancelBondProcess(BluetoothDevice device) { try { Method cancelBondMethod = BluetoothDevice.class.getMethod("cancelBondProcess"); Boolean returnValue = (Boolean) cancelBondMethod.invoke(device); return returnValue.booleanValue(); } catch (Exception e) { e.printStackTrace(); } return false; } //取消用戶輸入 public static boolean cancelPairingUserInput(BluetoothDevice device) { try { Method cancelPairingUserInputMethod = BluetoothDevice.class.getMethod("cancelPairingUserInput"); Boolean returnValue = (Boolean) cancelPairingUserInputMethod.invoke(device); return returnValue.booleanValue(); } catch (Exception e) { e.printStackTrace(); } return false; }
//注冊藍牙接收廣播 if (!hasRegister) { hasRegister = true; //掃描結束廣播 IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED); //找到設備廣播 filter.addAction(BluetoothDevice.ACTION_FOUND); filter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED); filter.addAction(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED); filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED); filter.addAction(BluetoothDevice.ACTION_PAIRING_REQUEST); registerReceiver(mMyReceiver, filter); }
private class MyReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (BluetoothDevice.ACTION_FOUND.equals(action)) { //搜索到新設備 BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); //搜索沒有配過對的藍牙設備 if (device.getBondState() != BluetoothDevice.BOND_BONDED) { mListData.add(device); dataAdapter.refreshData(mListData); } else { T.showLong(TwoActivity.this, device.getName() + '\n' + device.getAddress() + " > 已發現"); } } else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) { //搜索結束 if (mListData.size() == 0) { T.showLong(TwoActivity.this, "沒有發現任何藍牙設備"); } progressDialog.dismiss(); scan.setText("重新掃描"); } else if (BluetoothDevice.ACTION_PAIRING_REQUEST.equals(action)) { if (TwoActivity.this.position != -1) { final BluetoothDevice device = mListData.get(TwoActivity.this.position); com.dk.bluetooth.tools.T.showLong(TwoActivity.this, device + " 配對成功"); EventBus.getDefault().post(new com.dk.bluetooth.tools.MyEvent()); } } } }
通訊需要建立信道,BluetoothServerSocket需要先啟動,監聽當前設備上的某UUID位置上的設備(阻塞到在此處),就跟windows的端口意思是一樣的。然後BluetoothSocket再啟動,根據對方的mac地址和對方監聽的UUID位置,啟動連接(也阻塞了),直到連上服務器了,就返回。服務器也一樣,直到有人來連接了,就返回。都會返回一個BluetoothSocket,然後從這個socket裡面獲取input和output流。服務器端了input流是客戶端的output流,另外一半也一樣。剩下的收發消息就是流的讀寫了,簡單吧。
下面貼出我的代碼,應為服務器端和客戶端啟動的方法不一樣,我分成了兩個線程,由於讀寫的功能一樣,我就共用了一套讀寫線程。根據這個思路看我的代碼。
/** * 初始化及啟動藍牙socket * * @param handler UI消息傳遞對象 * @param securityType 連接的安全模式 * @param serverOrClient 客戶端或服務端 * @param bluetoothDevice 服務器端設備 */ public BluetoothChatService(Handler handler, SecurityType securityType, ServerOrClient serverOrClient, BluetoothDevice bluetoothDevice) { if (securityType != null) this.mSecurityType = securityType; if (serverOrClient != null) this.mServerOrClient = serverOrClient; if (bluetoothDevice != null) this.mBluetoothDevice = bluetoothDevice; mAdapter = BluetoothAdapter.getDefaultAdapter(); mHandler = handler; start(); } /** * 多線程同步修改狀態標識 * * @param state */ private synchronized void setState(int state) { mState = state; mHandler.obtainMessage(MESSAGE_TOAST_STATE_CHANGE, state, -1, null).sendToTarget(); } /** * 多線程同步讀取狀態標識 */ public synchronized int getState() { return mState; } /** * 啟動服務 */ public void start() { start(null, null, null); } /** * 啟動服務 * * @param securityType 連接的安全模式 * @param serverOrClient 客戶端或服務端 * @param bluetoothDevice 服務器端設備 */ public void start(SecurityType securityType, ServerOrClient serverOrClient, BluetoothDevice bluetoothDevice) { if (securityType != null) this.mSecurityType = securityType; if (this.mSecurityType == null) { if (DEBUG) Log.e(TAG, "mSecurityType cannot be null"); mHandler.obtainMessage(MESSAGE_TOAST_ERROR, -1, -1, "mSecurityType cannot be null").sendToTarget(); return; } if (serverOrClient != null) this.mServerOrClient = serverOrClient; if (this.mServerOrClient == null) { if (DEBUG) Log.e(TAG, "mServerOrClient cannot be null"); mHandler.obtainMessage(MESSAGE_TOAST_ERROR, -1, -1, "mServerOrClient cannot be null").sendToTarget(); return; } if (bluetoothDevice != null) this.mBluetoothDevice = bluetoothDevice; if (this.mBluetoothDevice == null) { if (DEBUG) Log.e(TAG, "mBluetoothDevice cannot be null"); mHandler.obtainMessage(MESSAGE_TOAST_ERROR, -1, -1, "mBluetoothDevice cannot be null").sendToTarget(); return; } if (mState == STATE_NONE) { stop(); if (this.mServerOrClient == ServerOrClient.SERVER) { if (mServerConnectThread == null) { mServerConnectThread = new ServerConnectThread(this.mSecurityType); mServerConnectThread.start(); } } else if (this.mServerOrClient == ServerOrClient.CLIENT) { if (mClientConnectThread == null) { mClientConnectThread = new ClientConnectThread(this.mSecurityType); mClientConnectThread.start(); } } setState(STATE_LISTEN); } } /** * 停止服務 */ public synchronized void stop() { try { if (mReadWriteThread != null) { mReadWriteThread.cancel(); mReadWriteThread = null; } if (mServerConnectThread != null) { mServerConnectThread.cancel(); mServerConnectThread = null; } if (mClientConnectThread != null) { mClientConnectThread.cancel(); mClientConnectThread = null; } } catch (Exception e) { e.printStackTrace(); if (DEBUG) Log.e(TAG, "BluetoothChatService -> stop() -> :failed " + e.getMessage()); mHandler.obtainMessage(MESSAGE_TOAST_ERROR, -1, -1, "BluetoothChatService -> stop() -> :failed").sendToTarget(); mReadWriteThread = null; mServerConnectThread = null; mClientConnectThread = null; } finally { setState(STATE_NONE); System.gc(); } } /** * 發送消息 * * @param out 數據參數 */ public void write(String out) { if (TextUtils.isEmpty(out)) { if (DEBUG) Log.e(TAG, "please write something now"); mHandler.obtainMessage(MESSAGE_TOAST_ERROR, -1, -1, "BluetoothChatService -> write() -> :failed").sendToTarget(); return; } ReadWriteThread r; synchronized (this) { if (mState != STATE_CONNECTED) return; r = mReadWriteThread; } r.write(out); } /** * 服務器端連接線程 */ @SuppressLint("NewApi") private class ServerConnectThread extends Thread { private BluetoothServerSocket mmServerSocket; private BluetoothSocket mmSocket = null; public ServerConnectThread(SecurityType securityType) { setName("ServerConnectionThread:" + securityType.getValue()); BluetoothServerSocket tmp = null; try { if (securityType == SecurityType.SECURE) { tmp = mAdapter.listenUsingRfcommWithServiceRecord(SecurityType.SECURE.getValue(), MY_UUID_SECURE); } else if (securityType == SecurityType.INSECURE) { tmp = mAdapter.listenUsingInsecureRfcommWithServiceRecord(SecurityType.INSECURE.getValue(), MY_UUID_INSECURE); } if (tmp != null) mmServerSocket = tmp; } catch (IOException e) { e.printStackTrace(); if (DEBUG) Log.e(TAG, "ServerConnectThread -> ServerConnectThread() -> :failed " + e.getMessage()); mHandler.obtainMessage(MESSAGE_TOAST_ERROR, -1, -1, "ServerConnectThread -> ServerConnectThread() -> :failed").sendToTarget(); mmServerSocket = null; BluetoothChatService.this.stop(); } } public void run() { try { // 正在連接 setState(STATE_CONNECTING); //accept() 阻塞式的方法,群聊時,需要循環accept接收客戶端 mmSocket = mmServerSocket.accept(); connected(mmSocket); } catch (Exception e) { e.printStackTrace(); if (DEBUG) Log.e(TAG, "ServerConnectThread -> run() -> :failed " + e.getMessage()); mHandler.obtainMessage(MESSAGE_TOAST_ERROR, -1, -1, "ServerConnectThread -> run() -> :failed").sendToTarget(); BluetoothChatService.this.stop(); } } public void cancel() { try { if (mmSocket != null) { mmSocket.close(); mmSocket = null; } if (mmServerSocket != null) { mmServerSocket.close(); mmServerSocket = null; } } catch (IOException e) { e.printStackTrace(); if (DEBUG) Log.e(TAG, "ServerConnectThread -> cancel() -> :failed " + e.getMessage()); mHandler.obtainMessage(MESSAGE_TOAST_ERROR, -1, -1, "ServerConnectThread -> cancel() -> :failed").sendToTarget(); mmSocket = null; mmServerSocket = null; BluetoothChatService.this.stop(); } } } // 客戶端連接線程 private class ClientConnectThread extends Thread { private BluetoothSocket mmSocket; public ClientConnectThread(SecurityType securityType) { setName("ClientConnectThread:" + securityType.getValue()); BluetoothSocket tmp = null; try { if (securityType == SecurityType.SECURE) { tmp = mBluetoothDevice.createRfcommSocketToServiceRecord(MY_UUID_SECURE); //Method m = mBluetoothDevice.getClass().getMethod("createRfcommSocket", int.class); //tmp = (BluetoothSocket) m.invoke(mBluetoothDevice, 1); } else if (securityType == SecurityType.INSECURE) { tmp = mBluetoothDevice.createInsecureRfcommSocketToServiceRecord(MY_UUID_INSECURE); //Method m = mBluetoothDevice.getClass().getMethod("createRfcommSocket", int.class); //tmp = (BluetoothSocket) m.invoke(mBluetoothDevice, 1); } if (tmp != null) mmSocket = tmp; } catch (Exception e) { e.printStackTrace(); if (DEBUG) Log.e(TAG, "ClientConnectThread -> ClientConnectThread() -> :failed " + e.getMessage()); mHandler.obtainMessage(MESSAGE_TOAST_ERROR, -1, -1, "ClientConnectThread -> ClientConnectThread() -> :failed").sendToTarget(); mmSocket = null; BluetoothChatService.this.stop(); } } public void run() { try { setState(STATE_CONNECTING); mmSocket.connect(); connected(mmSocket); } catch (IOException e) { e.printStackTrace(); if (DEBUG) Log.e(TAG, "ClientConnectThread -> run() -> :failed " + e.getMessage()); mHandler.obtainMessage(MESSAGE_TOAST_ERROR, -1, -1, "ClientConnectThread -> run() -> :failed").sendToTarget(); BluetoothChatService.this.stop(); } } public void cancel() { try { if (mmSocket != null && mmSocket.isConnected()) { mmSocket.close(); } mmSocket = null; } catch (IOException e) { e.printStackTrace(); if (DEBUG) Log.e(TAG, "ClientConnectThread -> cancel() -> :failed " + e.getMessage()); mHandler.obtainMessage(MESSAGE_TOAST_ERROR, -1, -1, "ClientConnectThread -> cancel() -> :failed").sendToTarget(); mmSocket = null; BluetoothChatService.this.stop(); } } } /** * 以獲取socket,建立數據流線程 * * @param socket */ private synchronized void connected(BluetoothSocket socket) { if (mReadWriteThread != null) { mReadWriteThread.cancel(); mReadWriteThread = null; } mReadWriteThread = new ReadWriteThread(socket); mReadWriteThread.start(); } /** * 連接成功線程,可進行讀寫操作 */ private class ReadWriteThread extends Thread { private BluetoothSocket mmSocket; private DataInputStream mmInStream; private DataOutputStream mmOutStream; private boolean isRunning = true; public ReadWriteThread(BluetoothSocket socket) { mmSocket = socket; try { mmInStream = new DataInputStream(mmSocket.getInputStream()); mmOutStream = new DataOutputStream(mmSocket.getOutputStream()); // 連接建立成功 setState(STATE_CONNECTED); } catch (IOException e) { e.printStackTrace(); if (DEBUG) Log.e(TAG, "ReadWriteThread -> ReadWriteThread() -> :failed " + e.getMessage()); mHandler.obtainMessage(MESSAGE_TOAST_ERROR, -1, -1, "ReadWriteThread -> ReadWriteThread() -> :failed").sendToTarget(); mmOutStream = null; mmInStream = null; BluetoothChatService.this.stop(); } } public void run() { byte[] buffer = new byte[1024]; int len; while (isRunning) { try { //readUTF(),read(buffer) 都是阻塞式的方法 //如果這兒用readUTF,那麼寫的地方得用writeUTF。對應 String receive_str = mmInStream.readUTF(); if (!TextUtils.isEmpty(receive_str)) mHandler.obtainMessage(MESSAGE_RECEIVE, -1, -1, receive_str).sendToTarget(); // len = mmInStream.read(buffer); // if(len > 0){ // String receive_str = new String(buffer,0,len); // if (!TextUtils.isEmpty(receive_str)) // mHandler.obtainMessage(MESSAGE_RECEIVE, -1, -1, receive_str).sendToTarget(); // } } catch (IOException e) { e.printStackTrace(); if (DEBUG) Log.e(TAG, "ReadWriteThread -> run() -> :failed " + e.getMessage()); mHandler.obtainMessage(MESSAGE_TOAST_ERROR, -1, -1, "ReadWriteThread -> run() -> :failed").sendToTarget(); BluetoothChatService.this.stop(); } } } public void write(String str) { try { mmOutStream.writeUTF(str); mmOutStream.flush(); mHandler.obtainMessage(MESSAGE_TOAST_SEND, -1, -1, str).sendToTarget(); } catch (IOException e) { e.printStackTrace(); if (DEBUG) Log.e(TAG, "ReadWriteThread -> write() -> :failed " + e.getMessage()); mHandler.obtainMessage(MESSAGE_TOAST_ERROR, -1, -1, "ReadWriteThread -> write() -> :failed").sendToTarget(); BluetoothChatService.this.stop(); } } public void cancel() { try { isRunning = false; if (mmInStream != null) { mmInStream.close(); mmInStream = null; } if (mmOutStream != null) { mmOutStream.close(); mmOutStream = null; } } catch (IOException e) { e.printStackTrace(); if (DEBUG) Log.e(TAG, "ReadWriteThread -> cancel() -> :failed " + e.getMessage()); mHandler.obtainMessage(MESSAGE_TOAST_ERROR, -1, -1, "ReadWriteThread -> cancel() -> :failed").sendToTarget(); mmInStream = null; mmOutStream = null; BluetoothChatService.this.stop(); } } }
下面貼出我的項目功能,是一個聊天程序,只能單聊。我不明太網上有很多demo聲稱能群聊怎麼實現的,據目前分析,服務器端和客戶端的管道流是一一對應的,不是廣播模式。如果能群聊,會在服務器端創建一個輸入輸出流管理的集合吧,服務器端沒收到一條消息,在=再循環輸出流集合,往各個客戶端都發送消息。這樣一來,我上面的這段代碼不夠用了。懶得改,故沒有做群聊。
先貼圖:
程序中,socket的連接方式有安全連接和不安全連接,我一直沒有搞懂區別
在兩個手機都連接了wifi的情況加,再使用我這種藍牙通訊方式通訊時,io流連接上後會自動斷開,很奇怪。查資料說藍牙通訊的波段頻率與路由器的沖突了。沒轍,故在啟動程序的時候關閉了wifi,下下策,望大家提供思路。
最近接了一個項目其中有功能要實現一個清理內存,要求和微信的效果一樣。於是想到用surfaceView而不是繼承view。下面小編給大家解析下實現思路。surfaceVie
其實Activity和fragment之間傳遞數據有很多方法,我這裡說一個用的比較多的一個方法——接口回調,後面有運行效果接口回調有幾個步驟:1,
本文主要講解局部加權(線性)回歸。在講解局部加權線性回歸之前,先講解兩個概念:欠擬合、過擬合,由此引出局部加權線性回歸算法。 欠擬合、過擬合如下圖中三個擬合模型
一、View動畫1、常見的4中View動畫:AlphaAnimation、ScaleAnimation、TranslateAnimation、RotateAnimatio