標籤:remote nio undle 方式 scan 內容 串連失敗 ble pair
吼。花了2天最後做出了一個類似於藍芽串口助手功能的小程式,事實上也是實習公司的要求---有一個藍芽無線掃描槍,要求終端能夠通過藍芽串連到該裝置,而且藍芽無線掃描槍掃描二維碼或者條碼的時候能夠將二維碼或者條碼的資料輸出到TextView中。
效果:
聽效果是不是感覺非常好做。說明下藍芽掃描器的功能,有2中經常使用的模式--普通模式,SPP模式。 普通模式的話就是相當於藍芽串連後,掃描器就相當於一個外接的鍵盤,能夠掃碼然後將資料輸出到EditText(必須獲得焦點)。SPP模式則是用於類比串口通訊的,在我看來就相當於開發人員模式。。
。
方案一:在介面代碼下手腳,是一種投機取巧的方法。
不是要顯示在TextVIew上嗎。不是要掃碼後僅僅能輸出到獲得焦點的EditText上嗎。那我就在介面代碼裡設定這兩個控制項。可是EditText我設定其高度為1dp。除了開發人員自己知道這裡有個EditText之外。使用者是不知道這裡還有個EditText的。
然後你就能夠直接將EditText中的內容擷取下來,在setText到TextView 中去就能夠了。
主要代碼就是Edittext的setOnKeyListener裡設定就好了。
et.setOnKeyListener(new EditText.OnKeyListener() { @Override publicboolean onKey(View v, int keyCode, KeyEvent event) { tv.setText(et.getText()); returnfalse; } });
操作簡單。思路清晰,簡單粗暴!可是問題也非常多,萬一你一個介面好多個EditText,比方登陸介面。除了你的那個自己知道別人看不到的EditText,還得有兩個EditText,一旦某一個獲得游標,你的掃描器就失去了作用,還會嚇使用者一跳。所以這樣的方案不適合用在須要推送的APP上。
方案二:藍芽傳輸通訊,詳細使用到的就是安卓傳輸的流方式,這樣的方式就非常符合要求,就在你要資料轉送的時候把你的資料截下來,然後我在做對應的操作。我看了非常多的部落格,說真的。這些部落格都千篇一律。這裡放兩篇比較經典的吧。
1190000004899799
http://www.cnblogs.com/wenjiang/p/3200138.html
詳細的解釋我會在代碼裡說。光說理論本人菜的摳腳。首先說說布局,超級簡單。一個TextView,一個EditText(測試用的) , 一個Button(能夠依據自己的須要去掉)。碼就不貼了,到時候直接發項目吧!
說說Button的點擊事件(能夠依據自己的需求進行改動)。點擊進入一個Activity顯示全部的掃描到的藍牙裝置--DeviceListAcitivty
一:擷取掃描到的藍牙裝置
DeviceListActivity裡面須要做的事情就是將能掃描到的藍牙裝置顯示在ListView中。假設你確定你僅僅要串連一種裝置的話而且知道裝置的Address的話你大可省略這個操作。這裡當學慣用。
import android.app.Activity;import android.bluetooth.BluetoothAdapter;import android.bluetooth.BluetoothDevice;import android.content.BroadcastReceiver;import android.content.Context;import android.content.Intent;import android.content.IntentFilter;import android.os.Bundle;import android.util.Log;import android.view.View;import android.view.Window;import android.view.View.OnClickListener;import android.widget.AdapterView;import android.widget.ArrayAdapter;import android.widget.Button;import android.widget.ListView;import android.widget.TextView;import android.widget.AdapterView.OnItemClickListener;public class DeviceListActivity extends Activity { // 調試用 private static final String TAG = "DeviceListActivity"; private static final boolean D = true; // 返回時資料標籤 public static String EXTRA_DEVICE_ADDRESS = "裝置地址"; // 成員域 private BluetoothAdapter mBtAdapter; private ArrayAdapter<String> mPairedDevicesArrayAdapter; private ArrayAdapter<String> mNewDevicesArrayAdapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // 建立並顯示表單 requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS); //設定表單顯示模式為表單方式 setContentView(R.layout.device_list); // 設定預設傳回值為取消 setResult(Activity.RESULT_CANCELED); // 設定掃描按鍵響應 Button scanButton = (Button) findViewById(R.id.button_scan); scanButton.setOnClickListener(new OnClickListener() { public void onClick(View v) { doDiscovery(); v.setVisibility(View.GONE); } }); // 初使化裝置儲存數組 mPairedDevicesArrayAdapter = new ArrayAdapter<>(this, R.layout.device_name); mNewDevicesArrayAdapter = new ArrayAdapter<>(this, R.layout.device_name); // 設定已配隊裝置列表 ListView pairedListView = (ListView) findViewById(R.id.paired_devices); pairedListView.setAdapter(mPairedDevicesArrayAdapter); pairedListView.setOnItemClickListener(mDeviceClickListener); // 設定新尋找裝置列表 ListView newDevicesListView = (ListView) findViewById(R.id.new_devices); newDevicesListView.setAdapter(mNewDevicesArrayAdapter); newDevicesListView.setOnItemClickListener(mDeviceClickListener); // 注冊接收尋找到裝置action接收器 IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND); this.registerReceiver(mReceiver, filter); // 注冊尋找結束action接收器 filter = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED); this.registerReceiver(mReceiver, filter); // 得到本地藍芽控制代碼 mBtAdapter = BluetoothAdapter.getDefaultAdapter(); // 得到已配對藍牙裝置列表 //Set<BluetoothDevice> pairedDevices = mBtAdapter.getBondedDevices(); // 加入已配對裝置到列表並顯示 // if (pairedDevices.size() > 0) { // findViewById(R.id.title_paired_devices).setVisibility(View.VISIBLE); // for (BluetoothDevice device : pairedDevices) { // mPairedDevicesArrayAdapter.add(device.getName() + "\n" + device.getAddress()); // } // } else { // String noDevices = "No devices have been paired"; // mPairedDevicesArrayAdapter.add(noDevices); // } } @Override protected void onDestroy() { super.onDestroy(); // 關閉服務尋找 if (mBtAdapter != null) { mBtAdapter.cancelDiscovery(); } // 登出action接收器 this.unregisterReceiver(mReceiver); } public void OnCancel(View v){ finish(); } /** * 開始服務和裝置尋找 */ private void doDiscovery() { if (D) Log.d(TAG, "doDiscovery()"); // 在表單顯示尋找中資訊 setProgressBarIndeterminateVisibility(true); setTitle("尋找裝置中..."); // 顯示其他裝置(未配對裝置)列表 findViewById(R.id.title_new_devices).setVisibility(View.VISIBLE); // 關閉再進行的服務尋找 if (mBtAdapter.isDiscovering()) { mBtAdapter.cancelDiscovery(); } //並又一次開始 mBtAdapter.startDiscovery(); } // 選擇裝置響應函數 private OnItemClickListener mDeviceClickListener = new OnItemClickListener() { public void onItemClick(AdapterView<?> av, View v, int arg2, long arg3) { // 準備串連裝置,關閉服務尋找 mBtAdapter.cancelDiscovery(); // 得到mac地址 String info = ((TextView) v).getText().toString(); String address = info.substring(info.length() - 17); // 設定返回資料 Intent intent = new Intent(); intent.putExtra(EXTRA_DEVICE_ADDRESS, address); // 設定傳回值並結束程式 setResult(Activity.RESULT_OK, intent); finish(); } }; // 尋找到裝置和搜尋完畢action監聽器 private final BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); // 尋找到裝置action if (BluetoothDevice.ACTION_FOUND.equals(action)) { // 得到藍牙裝置 BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); // 假設是已配對的則略過,已得到顯示,其餘的在加入到列表中進行顯示 if (device.getBondState() != BluetoothDevice.BOND_BONDED) { mNewDevicesArrayAdapter.add(device.getName() + "\n" + device.getAddress()); }else{ //加入到已配對裝置列表 mPairedDevicesArrayAdapter.add(device.getName() + "\n" + device.getAddress()); } // 搜尋完畢action } else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) { setProgressBarIndeterminateVisibility(false); setTitle("選擇要串連的裝置"); if (mNewDevicesArrayAdapter.getCount() == 0) { String noDevices = "沒有找到新裝置"; mNewDevicesArrayAdapter.add(noDevices); } // if(mPairedDevicesArrayAdapter.getCount() > 0) // findViewById(R.id.title_paired_devices).setVisibility(View.VISIBLE); } } };}
代碼貼在上面。詳細的代碼解釋也寫在代碼上了,事實上我後面是不打算做這部操作的,由於針對僅僅須要串連一個藍牙裝置的程式來說,當我知道了藍牙裝置的Mac地址我就能夠直接找到裝置,根本不須要查詢。但不得不說回來。 當廠家沒有給你藍牙裝置的Mac地址的時候。你就不得不做這步操作了!所以推薦的話還是把這步操作給做了的好,詳細怎麼操作還是得看項目的要求。至於怎樣尋找藍牙裝置以及藍牙裝置的狀態,上面的代碼寫的非常詳細,結合我之前推薦的兩篇文章就非常好懂了。
二:傳輸資料I/O流 事實上在做這步操作的時候,我有點操心實現不了,由於對於Socket來說。你至少得寫Socket和ServerSocket這兩個類,詳細的能夠看看我之前對Socket的部落格http://blog.csdn.net/cuihaoren01/article/details/45458265。但這裡藍芽掃描槍那邊你是不可能編程的的。所以不存在ServerSocket的,好像網上大部分的藍芽傳輸都是和Ardunio進行傳輸的,我也不曉得它可不能夠進行編程所以就非常操心這樣寫能不能實現。後面我在GitHub上找到一個藍芽串口助手的Demo來試試,發現它能夠進行資料傳送
但因為它寫的代碼過於複雜也不是一個架構能夠直接利用,所以就沒有深究。
https://github.com/hzjerry/BluetoothSppPro。
沒辦法了。實踐是檢驗真理的唯一標準那就僅僅能開始自己測試了,接下來第二篇文章就發揮了作用,可能我不須要實現ServerSocket服務端的編程,在使用藍芽串口助手測試的時候,你配對上加串連上就能夠直接用了。說明我僅僅須要和它(藍芽槍)能串連上就好了。
串連的做法過程例如以下:
- 首先你得擷取到你須要串連的裝置。
(這裡就須要你得裝置的Mac地址)
- 你須要建立與服務端通訊的Socket。看我之前的部落格client都是通過IP和port來獲得的通訊的socket,服務端是通過accept()的方式擷取的,而這裡這樣的方式被斃了(感覺也不能說斃了。預計是藍芽槍那邊有一個ServerSocket,去accept(),而client有其它的方法拿到通訊的Socket。
)
- socket.connect()
btn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mBluetoothDevice = mBluetoothAdapter.getRemoteDevice(address); try{ mBluetoothSocket = mBluetoothDevice. createRfcommSocketToServiceRecord (UUID.fromString(MY_UUID)); }catch (IOException e){ Toast.makeText(MainActivity.this, "配對失敗,原因是:" + e.getMessage(), Toast.LENGTH_SHORT) .show(); Log.e("過程", "失敗的原因是:" + e.getMessage()); } //與裝置進行串連 try{ mBluetoothSocket.connect(); Toast.makeText(MainActivity.this, "串連"+ mBluetoothDevice.getName() + "成功", Toast.LENGTH_SHORT).show(); Log.e("TAGGGAGGAGGHG","串連過程"); } catch (IOException e) { try{ Toast.makeText(MainActivity.this, "串連失敗,原因是:" + e.getMessage(), Toast.LENGTH_SHORT).show(); mBluetoothSocket.close(); mBluetoothSocket = null; Log.e("串連失敗", "串連失敗的原因是:" + e.getMessage()); } catch (IOException e1) { e1.printStackTrace(); } return; } //與裝置進行傳輸資料 try{ is = mBluetoothSocket.getInputStream(); }catch (IOException e){ Toast.makeText(MainActivity.this, "接收資料失敗", Toast.LENGTH_SHORT).show(); return; } if(ready_receive == false){ ReadThread.start(); ready_receive = true; }else { isReceiving = true; } } });
這一部分就是串連藍牙裝置的操作,本來這些操作我是放到一個線程中去啟動並執行。可是非常不幸的是會報錯,然後我就放到UI線程中去了,結果還過了,按道理耗時操作放到UI線程中不是會爆炸的嘛...臨時放一放這個問題。然後另一個線程ReadThread
Thread ReadThread = new Thread(){ public void run(){ int num = 0; byte[] buffer = new byte[1024]; byte[] buffer_new = new byte[1024]; int n = 0; isReceiving= true; while(true){ try { while (is.available() == 0){ while (isReceiving == false){} } while(true){ num = is.read(buffer); n = 0; String s0 = new String(buffer, 0, num);// fmsg += s0; for (int i = 0; i < num; i++ ){ if((buffer[i] == 0x0d) && (buffer[i + 1] == 0x0a)){ buffer_new[n] = 0x0a; i++; }else{ buffer_new[n] = buffer[i]; } n++; } String s = new String(buffer_new, 0, n); receive_msg += s; if (is.available() == 0) break; } handler.sendMessage(handler.obtainMessage()); }catch (IOException e){ } } } };
這樣就完畢了藍芽串口助手的部分功能,詳細的執行個體見原始碼下載。
原始碼下載:已知要串連裝置的address,僅僅須要改動MainActivity中address字串的值就能夠了。
http://download.csdn.net/detail/cuihaoren01/9496677
掃描藍牙裝置,選擇須要串連的裝置,進行傳輸。
http://download.csdn.net/detail/cuihaoren01/9496711
Android開發學習秘籍筆記(十九)