項目中的“藍牙”

           之前寫過一篇關於藍牙的文章,我把它稱爲譯文,就是把官方的BluetoothChat那個程序拿過來說android中的藍牙的操作。因爲項目要用到藍牙,所以這方面的文章看得也不少,不過果然文章都是大同小異,基本都是那個藍牙聊天程序的照抄,然後修改一下而已。所以當我做這個項目的時候,就很頭痛,因爲沒有多少可以參考的資料,所以一直研究那個聊天程序,現在算是,徹底弄懂了藍牙的所有操作部分。當然我這篇文章不是想說那個程序,我是想說說我那個項目中的藍牙操作,希望能給點不一樣的藍牙資料,供做項目的學習,也算是一種思路吧。

    直接說我那個項目對藍牙的要求。這是一個軌道磨耗檢測上位機程序,和下位機通信用的藍牙。協議部分是這樣的,首先在登陸進去的activity裏面建立藍牙連接,重點和核心是在整個程序的運行中要保證連接一直存在,也許你們不懂,這麼說吧,就是我這裏面有很多操作的activity,拿測量這一項來說,首先是用戶選擇線路的這個activity,然後纔是測量的10個值的顯示activity,還有測量值的繪圖activity,這只是測量,還有數據庫查詢等等。爲什麼說這是重點呢?想想那個藍牙聊天程序,它其實只是在主activity那裏實現通信的,當然我相信你不會提議每個activity都建立一次連接這麼傻的問題。協議還沒說完,建立連接只是第一步,建立連接之後,在測量activity,我們要給下位機發送開始測量的指令碼,然後下位機把這段指令碼回發,當接收到這段指令碼,纔開始發送測量數據指令,然後返回的就是數據。這裏有兩點,第一,上位機是一直在發送測量數據指令,(隔100ms,下位機接收和發送有延時);第二,接收到的數據要CRC校驗,校驗通過才能顯示在界面上,錯誤數據要拋棄。

    上面說了很多,表達能力不行,直接簡單的上圖說吧。

    第一副圖是登陸界面進去的第一個activity,藍牙是在這裏面建立連接,並一直保持,在整個程序的運行中。第二幅圖是線路檢測裏面的第二個界面,要把下位機上的這些數據都要讀出來,因爲下位機是一直在測量,所以顯示也是動態變化的。之前我模仿藍牙聊天程序在第二幅圖的界面做了藍牙建立,很簡單就成功了,可以和下位機通信,要求都滿足,但是問題在於,每次用戶換一個地點測量新數據,就要重現連接一次設備,然後才能開始測量。這麼麻煩,作爲成品是不能忍受的,所以也就要求:一次連接,保證不退出程序就可以一直使用藍牙,這是這篇文章的重點。

    首先在第一副圖建立藍牙連接不難做到,參考藍牙聊天程序都可以實現。在以後的過程中都要保持連接,我把它理解爲,我們在第一副圖那個界面實例化的bluetoothservice的一個實例在以後的任何一個activity中都要用到,所以我用的方法是把這個實例變成“全局變量”,也就是保存在application中的變量,然後我在測量這個activity中要用到藍牙,所以拿出這個全局變量,就保證了這個連接是一次連接,以後每個activity都是可用的。這裏不深說全局變量,其實也沒什麼特別,也算是android數據傳遞的一種方法。給出部分程序:

public class MyApp extends Application {

	private String correct13 = "0";
	private String correct25 = "0";
	private String correct48 = "0";
	private String correct65 = "0";
	private BluetoothService mChatService = null;
	
	public String[] getcorrect(){
		String[] str = new String[5];
		str[0] = correct13;
		str[1] = correct25;
		str[3] = correct48;
		str[4] = correct65;
		return str;
	};
	
	public void setcorrect(String[] str){
		this.correct13 = str[0];
		this.correct25 = str[1];
		this.correct48 = str[3];
		this.correct65 = str[4];
	}
	
	public BluetoothService getservice(){
		return mChatService;
	}
	
	public void setservice(BluetoothService service){
		this.mChatService = service;
	}
	

	
}

    第一副圖那個activity中設置這個service,在測量那個activity中獲取這個service。

MyApp app = (MyApp)getApplicationContext();
		app.setservice(mChatService);

MyApp app = (MyApp)getApplicationContext();
		mChatService = app.getservice();

    接下來說的是數據傳輸。上面的設置成全局變量只能保證發送指令是沒有問題的,但是接收讀取數據,這個是有問題的。因爲handler傳遞的數據是傳到第一副圖的那個activity中的,而不是測量那個activity中。但是顯示卻是在測量那個activity中顯示,這就是問題所在,這麼說應該能懂。至於爲什麼傳遞的下位機的數據是到第一個activity而不是測量那個activity,這個其實很簡單,因爲是在第一個activity中實例化的service,看藍牙聊天程序就知道實例化時是要傳入context和handler的,這個handler是在第一個activity中申明的,所以,只能傳給第一個activity。

    那能不能也用全局變量把第一個activity裏面的handler的數據變成全局的呢?其實是不行的,因爲這是一個動態的數據顯示,就是下位機一直在發送數據,而不是發一次,handler更新了數據,但是不能更新全局變量裏面的數據,所以做不到在測量activity裏面獲取到動態數據。

    對於上面分析,其實可以明白重點就是怎麼動態傳遞數據這個問題,何不考慮broadcastreceiver呢?是的,我用的就是廣播機制,把handler的數據廣播出去,接收到下位機數據就廣播一次,然後在測量activity裏面接收廣播,然後把數據處理顯示出來,思路就是這樣。部分代碼如下:

public void send(byte[] readBuf){
			
		    Intent intent = new Intent("android.intent.action.MY_BROADCAST");  
		    intent.putExtra("data", readBuf);  
		    sendBroadcast(intent);  
		    Log.i("chz", "發了");

		}

    這是發送廣播。

//廣播
  	 public class myReceiver extends BroadcastReceiver{
  		 
		public void onReceive(Context context, Intent intent) {
			        	
			readBuf = intent.getByteArrayExtra("data");			        	
			Log.i("chz", "收到了");
			String kaishicl = new String(bytesHexTobytes(readBuf));
			if(kaishicl.equals("01060001FFFFD9BA000000000000000000000000000000")){
			            	mHander.post(mRunnable);
			}else{
			//construct a string from the valid bytes in the buffer
			 byte[] newbytes = new byte[readBuf.length - 2];//獲取不含校驗位的字節數組
			 System.arraycopy(readBuf, 0, newbytes, 0, readBuf.length - 2);
			 String read = new String(bytesHexTobytes(newbytes));
			 String checkMessage = CRC16M.getBufHexStr(CRC16M.getSendBuf(read));//得到生成的校驗後字符串
			 String readMessage = new String(bytesHexTobytes(readBuf));
			          		
			 if(checkMessage.equals(readMessage)){//比較兩個字符串是否相等

			String guangliangdaichoice = guangliangdai.getSelectedItem().toString();
			if(guangliangdaichoice.equals("光亮帶位置(mm)")){
			      //光亮帶位置
			     String guangliangdaiweizhiets = showlight(readBuf[17],readBuf[18]);
			     guangliangdaiet.setText(guangliangdaiweizhiets);
			}else{
			      //光亮帶寬度
			     Cursor cursor = sqlitedb.rawQuery("select * from data", null);
			     int id = 1;
			     while(cursor.moveToNext()){
			     id++;
			    };
			    Cursor cur = sqlitedb.rawQuery("select * from data where id = " + Integer.toString(id-1), null);
			    String temp = "";
			    while(cur.moveToNext()){
			    	   temp += cur.getString(13);
			    }
			    	    			
			    String value = showlight(readBuf[17],readBuf[18]);
			    double former = Double.parseDouble(temp);
			    double laster = Double.parseDouble(value);
			    String guangliangdaikuanduets = String.valueOf((double)(Math.round((laster - former)*100)/100.0)); 
			    guangliangdaiet.setText(guangliangdaikuanduets);
			    }
			    display(readBuf);
			    }else{
			         Log.i("chz","校驗錯誤!");
			    }
	         	}
			            
		}
  	 }

     這是廣播的操作,還好這個操作不是耗時的,所以無所謂。

	IntentFilter filter = new IntentFilter();
        filter.addAction("android.intent.action.MY_BROADCAST");
        this.registerReceiver(myreceiver, filter);

     這個添加一個過濾器獲取確定的廣播。
   

     嗯,其實我這裏只是提供一個思路來解決遇到的問題,相信大家也會有自己的方法和思路。





   

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章