android自帶藍牙例子詳解


相關參考網站:http://wenku.baidu.com/view/d901cc2d4b73f242336c5f87.html

                  

http://wenku.baidu.com/view/518414b069dc5022aaea007b.html?from=rec&pos=2&weight=167&lastweight=111&count=5

http://wenku.baidu.com/view/dec9bddd5022aaea998f0f7f.html

測試藍牙程序需要至少2個真機,然而Android 2.0以后才真正支持藍牙設備編程。為了給這一講配圖,我要先去把HTC G4 刷一下機,經過2天的折騰,終於把G4刷到Android 2.2版本了…… 開始寫本講……

image

藍牙是一種設備短距離無線通信技術,使用藍牙你可以搜索並連接到附近的藍牙設備,可以在兩個已經進行過配對的藍牙設備之間進行數據傳輸。

本講我們先使用Android SDK自帶的例子藍牙聊天程序BluetoothChat來做演示。源代碼具體位置\android-sdk-windows\samples\android-8\BluetoothChat目錄下。然后再自己實現一邊這個藍牙聊天程序。

一、SDK自帶例子,BluetoothChat 的運行演示

這一次我們先看一下運行效果:准備兩個真機 Milestone 和 HTC G4 Tattoo,分別安裝好Bluetooth程序,
先在 Milestone上點擊 BluetoothChat 運行程序,

image

提示需要藍牙使用權限

image

選擇是,打開藍牙,進入聊天界面,只是此時還未連接任何藍牙設備。在HTC G4上進行同樣的操作,也進入not connected 狀態。

image

點擊Menu按鈕呼出菜單

image

點擊 Make discoverable 菜單使,並在彈出的權限請求對話框中選擇是,使手機可以被其它藍牙設備發現,G4也做同樣操作

image

然后選擇connect a device,在彈出的對話框中選擇 Scan for devices 查找設備,會發現 HTC Tattoo 設備

image

image

image

image

全部選擇匹配,然后就連接成功了。

image

image

這樣就可以聊天了……

MainFest xml

Xhtml代碼 復制代碼
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <!-- Copyright (C) 2009 The Android Open Source Project   
  3.      Licensed under the Apache License, Version 2.0 (the "License");   
  4.      you may not use this file except in compliance with the License.   
  5.      You may obtain a copy of the License at   
  6.           http://www.apache.org/licenses/LICENSE-2.0   
  7.      Unless required by applicable law or agreed to in writing, software   
  8.      distributed under the License is distributed on an "AS IS" BASIS,   
  9.      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   
  10.      See the License for the specific language governing permissions and   
  11.      limitations under the License.   
  12. -->  
  13. <manifest xmlns:android="http://schemas.android.com/apk/res/android"  
  14.       package="com.example.android.BluetoothChat"  
  15.       android:versionCode="1"  
  16.       android:versionName="1.0">  
  17.     <uses-sdk minSdkVersion="6" />  
  18.     <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />  
  19.     <uses-permission android:name="android.permission.BLUETOOTH" />  
  20.     <!-- 獲取權限BlueTooth-->  
  21.     <application android:label="@string/app_name"  
  22.                  android:icon="@drawable/app_icon" >  
  23.         <activity android:name=".BluetoothChat"  
  24.                   android:label="@string/app_name"  
  25.                   android:configChanges="orientation|keyboardHidden">  
  26.             <intent-filter>  
  27.                 <action android:name="android.intent.action.MAIN" />  
  28.                 <category android:name="android.intent.category.LAUNCHER" />  
  29.             </intent-filter>  
  30.         </activity>  
  31.         <activity android:name=".DeviceListActivity"  
  32.                   android:label="@string/select_device"  
  33.                   android:theme="@android:style/Theme.Dialog"                 
  34.                   android:configChanges="orientation|keyboardHidden" />  
  35.                       <!-- android:theme="@android:style/Theme.Dialog" 設置界面主題:彈出框主題 -->  
  36.     </application>  
  37. </manifest>  

 

Java代碼 復制代碼
  1. /*  
  2.  * Copyright (C) 2009 The Android Open Source Project  
  3.  *  
  4.  * Licensed under the Apache License, Version 2.0 (the "License");  
  5.  * you may not use this file except in compliance with the License.  
  6.  * You may obtain a copy of the License at  
  7.  *  
  8.  *      http://www.apache.org/licenses/LICENSE-2.0  
  9.  *  
  10.  * Unless required by applicable law or agreed to in writing, software  
  11.  * distributed under the License is distributed on an "AS IS" BASIS,  
  12.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  
  13.  * See the License for the specific language governing permissions and  
  14.  * limitations under the License.  
  15.  */  
  16. package com.example.android.BluetoothChat;   
  17. import android.app.Activity;   
  18. import android.bluetooth.BluetoothAdapter;   
  19. import android.bluetooth.BluetoothDevice;   
  20. import android.content.Intent;   
  21. import android.os.Bundle;   
  22. import android.os.Handler;   
  23. import android.os.Message;   
  24. import android.util.Log;   
  25. import android.view.KeyEvent;   
  26. import android.view.Menu;   
  27. import android.view.MenuInflater;   
  28. import android.view.MenuItem;   
  29. import android.view.View;   
  30. import android.view.Window;   
  31. import android.view.View.OnClickListener;   
  32. import android.view.inputmethod.EditorInfo;   
  33. import android.widget.ArrayAdapter;   
  34. import android.widget.Button;   
  35. import android.widget.EditText;   
  36. import android.widget.ListView;   
  37. import android.widget.TextView;   
  38. import android.widget.Toast;   
  39. /**  
  40.  * This is the main Activity that displays the current chat session.  
  41.  */  
  42. public class BluetoothChat extends Activity {   
  43.     // Debugging   
  44.     private static final String TAG = "BluetoothChat";   
  45.     private static final boolean D = true;   
  46.     // Message types sent from the BluetoothChatService Handler   
  47.     public static final int MESSAGE_STATE_CHANGE = 1;   
  48.     public static final int MESSAGE_READ = 2;   
  49.     public static final int MESSAGE_WRITE = 3;   
  50.     public static final int MESSAGE_DEVICE_NAME = 4;   
  51.     public static final int MESSAGE_TOAST = 5;   
  52.     // Key names received from the BluetoothChatService Handler   
  53.     public static final String DEVICE_NAME = "device_name";   
  54.     public static final String TOAST = "toast";   
  55.     // Intent request codes   
  56.     private static final int REQUEST_CONNECT_DEVICE = 1;   
  57.     private static final int REQUEST_ENABLE_BT = 2;   
  58.     // Layout Views   
  59.     private TextView mTitle;   
  60.     private ListView mConversationView;   
  61.     private EditText mOutEditText;   
  62.     private Button mSendButton;   
  63.     // Name of the connected device   
  64.     private String mConnectedDeviceName = null;   
  65.     // Array adapter for the conversation thread   
  66.     private ArrayAdapter<String> mConversationArrayAdapter;   
  67.     // String buffer for outgoing messages   
  68.     private StringBuffer mOutStringBuffer;   
  69.     // Local Bluetooth adapter   
  70.     private BluetoothAdapter mBluetoothAdapter = null;   
  71.     // Member object for the chat services   
  72.     private BluetoothChatService mChatService = null;   
  73.   
  74.     @Override  
  75.     public void onCreate(Bundle savedInstanceState) {   
  76.         super.onCreate(savedInstanceState);   
  77.         if(D) Log.e(TAG, "+++ ON CREATE +++");   
  78.         // Set up the window layout 設置Activity的標題欄格式Window.FEATURE_CUSTOM_TITLE普通、Window.FEATURE_NO_TITLE無標題欄、Window.FEATURE_INDETERMINATE_PROGRESS進度條   
  79.         requestWindowFeature(Window.FEATURE_CUSTOM_TITLE);   
  80.         setContentView(R.layout.main);   
  81.         //設置標題欄的布局資源   
  82.         getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE, R.layout.custom_title);   
  83.            
  84.         // Set up the custom title   
  85.         mTitle = (TextView) findViewById(R.id.title_left_text);   
  86.         mTitle.setText(R.string.app_name);   
  87.         mTitle = (TextView) findViewById(R.id.title_right_text);   
  88.         // Get local Bluetooth adapter   
  89.        //從根本上講,這是你的出發點,所有的藍牙行動。一旦你的本地適配器,getBondedDevices()所有配對設備對象設置;   
  90.         //與startDiscovery()啟動設備可被發現,或建立一個BluetoothServerSocket監聽與listenUsingRfcommWithServiceRecord(字符串,UUID的)傳入的連接請求。   
  91.         mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();   
  92.         // If the adapter is null, then Bluetooth is not supported   
  93.         if (mBluetoothAdapter == null) {   
  94.             Toast.makeText(this"Bluetooth is not available", Toast.LENGTH_LONG).show();   
  95.             finish();   
  96.             return;   
  97.         }   
  98.     }   
  99.     @Override  
  100.     public void onStart() {   
  101.         super.onStart();   
  102.         if(D) Log.e(TAG, "++ ON START ++");   
  103.         // If BT is not on, request that it be enabled.   
  104.         // setupChat() will then be called during onActivityResult   
  105.         //判斷藍牙是否開啟,否則請求開啟   
  106.         if (!mBluetoothAdapter.isEnabled()) {   
  107.             Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);   
  108.             startActivityForResult(enableIntent, REQUEST_ENABLE_BT);   
  109.         // Otherwise, setup the chat session   
  110.         } else {   
  111.             if (mChatService == null) setupChat();   
  112.         }   
  113.     }   
  114.     @Override  
  115.     public synchronized void onResume() {   
  116.         super.onResume();   
  117.         if(D) Log.e(TAG, "+ ON RESUME +");   
  118.         // Performing this check in onResume() covers the case in which BT was   
  119.         // not enabled during onStart(), so we were paused to enable it...   
  120.         // onResume() will be called when ACTION_REQUEST_ENABLE activity returns.   
  121.         if (mChatService != null) {   
  122.             // Only if the state is STATE_NONE, do we know that we haven't started already   
  123.             if (mChatService.getState() == BluetoothChatService.STATE_NONE) { //STATE_NONE及剛創建為啟動狀態,如果是從后台切換到前台應為STATE_LISTEN,無需再次啟動   
  124.               // Start the Bluetooth chat services    
  125.               mChatService.start();   
  126.             }   
  127.         }   
  128.     }   
  129.     private void setupChat() {   
  130.         Log.d(TAG, "setupChat()");   
  131.         // Initialize the array adapter for the conversation thread    
  132.         mConversationArrayAdapter = new ArrayAdapter<String>(this, R.layout.message);   
  133.         mConversationView = (ListView) findViewById(R.id.in);   
  134.         mConversationView.setAdapter(mConversationArrayAdapter);   
  135.         // Initialize the compose field with a listener for the return key   
  136.         mOutEditText = (EditText) findViewById(R.id.edit_text_out);   
  137.         mOutEditText.setOnEditorActionListener(mWriteListener);////注冊編輯狀態監聽   
  138.         // Initialize the send button with a listener that for click events   
  139.         mSendButton = (Button) findViewById(R.id.button_send);   
  140.         mSendButton.setOnClickListener(new OnClickListener() {   
  141.             public void onClick(View v) {   
  142.                 // Send a message using content of the edit text widget   
  143.                 TextView view = (TextView) findViewById(R.id.edit_text_out);   
  144.                 String message = view.getText().toString();   
  145.                 sendMessage(message); //點擊發送則向藍牙發送消息   
  146.             }   
  147.         });   
  148.         // Initialize the BluetoothChatService to perform bluetooth connections   
  149.         mChatService = new BluetoothChatService(this, mHandler);   
  150.         // Initialize the buffer for outgoing messages   
  151.         mOutStringBuffer = new StringBuffer("");   
  152.     }   
  153.     @Override  
  154.     public synchronized void onPause() {   
  155.         super.onPause();   
  156.         if(D) Log.e(TAG, "- ON PAUSE -");   
  157.     }   
  158.     @Override  
  159.     public void onStop() {   
  160.         super.onStop();   
  161.         if(D) Log.e(TAG, "-- ON STOP --");   
  162.     }   
  163.     @Override  
  164.     public void onDestroy() {   
  165.         super.onDestroy();   
  166.         // Stop the Bluetooth chat services   
  167.         if (mChatService != null) mChatService.stop(); //UI關閉時,藍牙服務應也停止   
  168.         if(D) Log.e(TAG, "--- ON DESTROY ---");   
  169.     }   
  170.     private void ensureDiscoverable() {   
  171.         if(D) Log.d(TAG, "ensure discoverable");   
  172.         if (mBluetoothAdapter.getScanMode() !=   
  173.             BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) { //如果藍牙狀態為不可被發現則請求開啟為可被發現,時間300秒內   
  174.             Intent discoverableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);   
  175.             discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);   
  176.             startActivity(discoverableIntent);   
  177.         }   
  178.     }   
  179.     /**  
  180.      * Sends a message.  
  181.      * @param message  A string of text to send.  
  182.      */  
  183.     private void sendMessage(String message) {   
  184.         // Check that we're actually connected before trying anything   
  185.         if (mChatService.getState() != BluetoothChatService.STATE_CONNECTED) {   
  186.             Toast.makeText(this, R.string.not_connected, Toast.LENGTH_SHORT).show();   
  187.             return;   
  188.         }   
  189.         // Check that there's actually something to send   
  190.         if (message.length() > 0) {   
  191.             // Get the message bytes and tell the BluetoothChatService to write   
  192.             byte[] send = message.getBytes();   
  193.             mChatService.write(send);   
  194.             // Reset out string buffer to zero and clear the edit text field   
  195.             mOutStringBuffer.setLength(0); //mOutStringBuffer 一直未使用,何意?   
  196.             mOutEditText.setText(mOutStringBuffer);//清空編輯框 竊以為使用mOutEditText.setText("");即可   
  197.         }   
  198.     }   
  199.     // The action listener for the EditText widget, to listen for the return key   
  200.     private TextView.OnEditorActionListener mWriteListener =   
  201.         new TextView.OnEditorActionListener() {   
  202.         public boolean onEditorAction(TextView view, int actionId, KeyEvent event) {   
  203.             // If the action is a key-up event on the return key, send the message    
  204.             //經測試應為點擊回車鍵后放開時發送消息   
  205.             if (actionId == EditorInfo.IME_NULL && event.getAction() == KeyEvent.ACTION_UP) {   
  206.                 String message = view.getText().toString();   
  207.                 sendMessage(message);   
  208.             }   
  209.             if(D) Log.i(TAG, "END onEditorAction");   
  210.             return true;   
  211.         }   
  212.     };   
  213.     // The Handler that gets information back from the BluetoothChatService   
  214.     //更新標題欄右邊狀態和讀寫狀態的Handler   
  215.     private final Handler mHandler = new Handler() {   
  216.         @Override  
  217.         public void handleMessage(Message msg) {   
  218.             switch (msg.what) {   
  219.             case MESSAGE_STATE_CHANGE:   
  220.                 if(D) Log.i(TAG, "MESSAGE_STATE_CHANGE: " + msg.arg1);   
  221.                 switch (msg.arg1) {   
  222.                 case BluetoothChatService.STATE_CONNECTED:   
  223.                     mTitle.setText(R.string.title_connected_to);   
  224.                     mTitle.append(mConnectedDeviceName);   
  225.                     mConversationArrayAdapter.clear(); //清空消息   
  226.                     break;   
  227.                 case BluetoothChatService.STATE_CONNECTING:   
  228.                     mTitle.setText(R.string.title_connecting);   
  229.                     break;   
  230.                 case BluetoothChatService.STATE_LISTEN:   
  231.                 case BluetoothChatService.STATE_NONE:   
  232.                     mTitle.setText(R.string.title_not_connected);   
  233.                     break;   
  234.                 }   
  235.                 break;   
  236.             case MESSAGE_WRITE:   
  237.                 byte[] writeBuf = (byte[]) msg.obj;   
  238.                 // construct a string from the buffer   
  239.                 String writeMessage = new String(writeBuf);   
  240.                 mConversationArrayAdapter.add("Me:  " + writeMessage);   
  241.                 break;   
  242.             case MESSAGE_READ:   
  243.                 byte[] readBuf = (byte[]) msg.obj;   
  244.                 // construct a string from the valid bytes in the buffer   
  245.                 String readMessage = new String(readBuf, 0, msg.arg1);   
  246.                 mConversationArrayAdapter.add(mConnectedDeviceName+":  " + readMessage);   
  247.                 break;   
  248.             case MESSAGE_DEVICE_NAME:   
  249.                 // save the connected device's name   
  250.                 mConnectedDeviceName = msg.getData().getString(DEVICE_NAME);   
  251.                 Toast.makeText(getApplicationContext(), "Connected to "  
  252.                                + mConnectedDeviceName, Toast.LENGTH_SHORT).show();   
  253.                 break;   
  254.             case MESSAGE_TOAST:   
  255.                 Toast.makeText(getApplicationContext(), msg.getData().getString(TOAST),   
  256.                                Toast.LENGTH_SHORT).show();   
  257.                 break;   
  258.             }   
  259.         }   
  260.     };   
  261.     public void onActivityResult(int requestCode, int resultCode, Intent data) {   
  262.         if(D) Log.d(TAG, "onActivityResult " + resultCode);   
  263.         switch (requestCode) {   
  264.         case REQUEST_CONNECT_DEVICE:   
  265.             // When DeviceListActivity returns with a device to connect   
  266.             if (resultCode == Activity.RESULT_OK) {   
  267.                 // Get the device MAC address   
  268.                 String address = data.getExtras()   
  269.                                      .getString(DeviceListActivity.EXTRA_DEVICE_ADDRESS);   
  270.                 // Get the BLuetoothDevice object   
  271.                 if(address==null){   
  272.                     break;   
  273.                 }   
  274.                 //獲取設備進行連接   
  275.                 BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);   
  276.                 // Attempt to connect to the device   
  277.                 mChatService.connect(device);   
  278.             }   
  279.             break;   
  280.         case REQUEST_ENABLE_BT:   
  281.             // When the request to enable Bluetooth returns   
  282.             if (resultCode == Activity.RESULT_OK) {   
  283.                 // Bluetooth is now enabled, so set up a chat session   
  284.                 //藍牙開啟成功,則繼續初始化UI   
  285.                 setupChat();   
  286.             } else {   
  287.                 // User did not enable Bluetooth or an error occured   
  288.                 Log.d(TAG, "BT not enabled");   
  289.                 Toast.makeText(this, R.string.bt_not_enabled_leaving, Toast.LENGTH_SHORT).show();   
  290.                 finish();   
  291.             }   
  292.         }   
  293.     }   
  294.     @Override  
  295.     public boolean onCreateOptionsMenu(Menu menu) {   
  296.         //從Menu資源中初始化Menu 返回true則彈出默認menu,false則不彈出Menu,須自定義   
  297.         MenuInflater inflater = getMenuInflater();   
  298.         inflater.inflate(R.menu.option_menu, menu);   
  299.         return true;    
  300.     }   
  301.     @Override  
  302.     public boolean onOptionsItemSelected(MenuItem item) {   
  303.         switch (item.getItemId()) {   
  304.         case R.id.scan:   
  305.             // Launch the DeviceListActivity to see devices and do scan   
  306.             //啟動DeviceListActivity,並等待返回   
  307.             Intent serverIntent = new Intent(this, DeviceListActivity.class);   
  308.             startActivityForResult(serverIntent, REQUEST_CONNECT_DEVICE);   
  309.             return true;   
  310.         case R.id.discoverable:   
  311.             // Ensure this device is discoverable by others   
  312.             ensureDiscoverable();   
  313.             return true;   
  314.         }   
  315.         return false;   
  316.     }   
  317. }  

 

Java代碼 復制代碼
  1. /*  
  2.  * Copyright (C) 2009 The Android Open Source Project  
  3.  *  
  4.  * Licensed under the Apache License, Version 2.0 (the "License");  
  5.  * you may not use this file except in compliance with the License.  
  6.  * You may obtain a copy of the License at  
  7.  *  
  8.  *      http://www.apache.org/licenses/LICENSE-2.0  
  9.  *  
  10.  * Unless required by applicable law or agreed to in writing, software  
  11.  * distributed under the License is distributed on an "AS IS" BASIS,  
  12.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  
  13.  * See the License for the specific language governing permissions and  
  14.  * limitations under the License.  
  15.  */  
  16. package com.example.android.BluetoothChat;   
  17. import java.util.Set;   
  18. import android.app.Activity;   
  19. import android.bluetooth.BluetoothAdapter;   
  20. import android.bluetooth.BluetoothDevice;   
  21. import android.content.BroadcastReceiver;   
  22. import android.content.Context;   
  23. import android.content.Intent;   
  24. import android.content.IntentFilter;   
  25. import android.os.Bundle;   
  26. import android.util.Log;   
  27. import android.view.View;   
  28. import android.view.Window;   
  29. import android.view.View.OnClickListener;   
  30. import android.widget.AdapterView;   
  31. import android.widget.ArrayAdapter;   
  32. import android.widget.Button;   
  33. import android.widget.ListView;   
  34. import android.widget.TextView;   
  35. import android.widget.AdapterView.OnItemClickListener;   
  36. /**  
  37.  * This Activity appears as a dialog. It lists any paired devices and  
  38.  * devices detected in the area after discovery. When a device is chosen  
  39.  * by the user, the MAC address of the device is sent back to the parent  
  40.  * Activity in the result Intent.  
  41.  */  
  42. public class DeviceListActivity extends Activity {   
  43.     // Debugging   
  44.     private static final String TAG = "DeviceListActivity";   
  45.     private static final boolean D = true;   
  46.     // Return Intent extra   
  47.     public static String EXTRA_DEVICE_ADDRESS = "device_address";   
  48.     // Member fields   
  49.     private BluetoothAdapter mBtAdapter;   
  50.     private ArrayAdapter<String> mPairedDevicesArrayAdapter;   
  51.     private ArrayAdapter<String> mNewDevicesArrayAdapter;   
  52.     @Override  
  53.     protected void onCreate(Bundle savedInstanceState) {   
  54.         super.onCreate(savedInstanceState);   
  55.         // Setup the window   
  56.         requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);   
  57.         setContentView(R.layout.device_list);   
  58.         // Set result CANCELED incase the user backs out   
  59.         //先設置為Canceled 防止點擊回退鍵時BluetoothChat認為是Result_OK狀態   
  60.         setResult(Activity.RESULT_CANCELED);   
  61.         // Initialize the button to perform device discovery   
  62.         Button scanButton = (Button) findViewById(R.id.button_scan);   
  63.         scanButton.setOnClickListener(new OnClickListener() {   
  64.             public void onClick(View v) {   
  65.                 doDiscovery();   
  66.                 v.setVisibility(View.GONE);   
  67.             }   
  68.         });   
  69.         // Initialize array adapters. One for already paired devices and   
  70.         // one for newly discovered devices   
  71.         mPairedDevicesArrayAdapter = new ArrayAdapter<String>(this, R.layout.device_name);   
  72.         mNewDevicesArrayAdapter = new ArrayAdapter<String>(this, R.layout.device_name);   
  73.         // Find and set up the ListView for paired devices   
  74.         ListView pairedListView = (ListView) findViewById(R.id.paired_devices);   
  75.         pairedListView.setAdapter(mPairedDevicesArrayAdapter);   
  76.         pairedListView.setOnItemClickListener(mDeviceClickListener);   
  77.         // Find and set up the ListView for newly discovered devices   
  78.         ListView newDevicesListView = (ListView) findViewById(R.id.new_devices);   
  79.         newDevicesListView.setAdapter(mNewDevicesArrayAdapter);   
  80.         newDevicesListView.setOnItemClickListener(mDeviceClickListener);   
  81.         // Register for broadcasts when a device is discovered 發現設備時監聽過濾   
  82.         IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);   
  83.         this.registerReceiver(mReceiver, filter);   
  84.         // Register for broadcasts when discovery has finished發現設備程序運行結束時監聽過濾   
  85.         filter = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);   
  86.         this.registerReceiver(mReceiver, filter);   
  87.         // Get the local Bluetooth adapter   
  88.         mBtAdapter = BluetoothAdapter.getDefaultAdapter();   
  89.         // Get a set of currently paired devices 獲取當前已經互聯過的設備   
  90.         Set<BluetoothDevice> pairedDevices = mBtAdapter.getBondedDevices();   
  91.         // If there are paired devices, add each one to the ArrayAdapter   
  92.         if (pairedDevices.size() > 0) {   
  93.             findViewById(R.id.title_paired_devices).setVisibility(View.VISIBLE);    
  94.             for (BluetoothDevice device : pairedDevices) {   
  95.                 mPairedDevicesArrayAdapter.add(device.getName() + "\n" + device.getAddress());   
  96.             }   
  97.         } else {   
  98.             String noDevices = getResources().getText(R.string.none_paired).toString();   
  99.             mPairedDevicesArrayAdapter.add(noDevices);   
  100.         }   
  101.     }   
  102.     @Override  
  103.     protected void onDestroy() {   
  104.         super.onDestroy();   
  105.         // Make sure we're not doing discovery anymore   
  106.         if (mBtAdapter != null) {   
  107.             mBtAdapter.cancelDiscovery(); //BluetoothAdapter 不受UI管理受系統管理,所以要即使cancelDiscovery   
  108.         }   
  109.         // Unregister broadcast listeners   
  110.         this.unregisterReceiver(mReceiver); //取消監聽當UI銷毀時   
  111.     }   
  112.     /**  
  113.      * Start device discover with the BluetoothAdapter  
  114.      */  
  115.     private void doDiscovery() {   
  116.         if (D) Log.d(TAG, "doDiscovery()");   
  117.         // Indicate scanning in the title 設置標題加載loading條可見   
  118.         setProgressBarIndeterminateVisibility(true);    
  119.         setTitle(R.string.scanning); //設置標題   
  120.         // Turn on sub-title for new devices   
  121.         findViewById(R.id.title_new_devices).setVisibility(View.VISIBLE);   
  122.         // If we're already discovering, stop it   
  123.         if (mBtAdapter.isDiscovering()) {   
  124.             mBtAdapter.cancelDiscovery();    
  125.         }   
  126.         // Request discover from BluetoothAdapter   
  127.         mBtAdapter.startDiscovery();   
  128.     }   
  129.     // The on-click listener for all devices in the ListViews 點擊藍牙列表的監聽   
  130.     private OnItemClickListener mDeviceClickListener = new OnItemClickListener() {   
  131.         public void onItemClick(AdapterView<?> av, View v, int arg2, long arg3) {   
  132.             // Cancel discovery because it's costly and we're about to connect   
  133.             mBtAdapter.cancelDiscovery();    
  134.             // Get the device MAC address, which is the last 17 chars in the View IP地址17位   
  135.             String info = ((TextView) v).getText().toString();   
  136.             String address = info.substring(info.length() - 17);   
  137.             // Create the result Intent and include the MAC address   
  138.             Intent intent = new Intent();   
  139.             intent.putExtra(EXTRA_DEVICE_ADDRESS, address);   
  140.             // Set result and finish this Activity   
  141.             setResult(Activity.RESULT_OK, intent);   
  142.             finish();   
  143.         }   
  144.     };   
  145.     // The BroadcastReceiver that listens for discovered devices and   
  146.     // changes the title when discovery is finished   
  147.     private final BroadcastReceiver mReceiver = new BroadcastReceiver() {   
  148.         @Override  
  149.         public void onReceive(Context context, Intent intent) {   
  150.             String action = intent.getAction();   
  151.             // When discovery finds a device 搜索到設備   
  152.             if (BluetoothDevice.ACTION_FOUND.equals(action)) {   
  153.                 // Get the BluetoothDevice object from the Intent   
  154.                 BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);   
  155.                 // If it's already paired, skip it, because it's been listed already   
  156.                 if (device.getBondState() != BluetoothDevice.BOND_BONDED) {   
  157.                     mNewDevicesArrayAdapter.add(device.getName() + "\n" + device.getAddress());   
  158.                 }   
  159.             // When discovery is finished, change the Activity title   
  160.             } else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) {    
  161.                 setProgressBarIndeterminateVisibility(false);//搜索完畢,loading條不可見   
  162.                 setTitle(R.string.select_device);   
  163.                 if (mNewDevicesArrayAdapter.getCount() == 0) {   
  164.                     String noDevices = getResources().getText(R.string.none_found).toString();   
  165.                     mNewDevicesArrayAdapter.add(noDevices);   
  166.                 }   
  167.             }   
  168.         }   
  169.     };   
  170. }  

 

Java代碼 復制代碼
  1. /*  
  2.  * Copyright (C) 2009 The Android Open Source Project  
  3.  *  
  4.  * Licensed under the Apache License, Version 2.0 (the "License");  
  5.  * you may not use this file except in compliance with the License.  
  6.  * You may obtain a copy of the License at  
  7.  *  
  8.  *      http://www.apache.org/licenses/LICENSE-2.0  
  9.  *  
  10.  * Unless required by applicable law or agreed to in writing, software  
  11.  * distributed under the License is distributed on an "AS IS" BASIS,  
  12.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  
  13.  * See the License for the specific language governing permissions and  
  14.  * limitations under the License.  
  15.  */  
  16. package com.example.android.BluetoothChat;   
  17. import java.io.IOException;   
  18. import java.io.InputStream;   
  19. import java.io.OutputStream;   
  20. import java.util.UUID;   
  21. import android.bluetooth.BluetoothAdapter;   
  22. import android.bluetooth.BluetoothDevice;   
  23. import android.bluetooth.BluetoothServerSocket;   
  24. import android.bluetooth.BluetoothSocket;   
  25. import android.content.Context;   
  26. import android.os.Bundle;   
  27. import android.os.Handler;   
  28. import android.os.Message;   
  29. import android.util.Log;   
  30. /**  
  31.  * This class does all the work for setting up and managing Bluetooth  
  32.  * connections with other devices. It has a thread that listens for  
  33.  * incoming connections, a thread for connecting with a device, and a  
  34.  * thread for performing data transmissions when connected.  
  35.  */  
  36. public class BluetoothChatService {   
  37.     // Debugging   
  38.     private static final String TAG = "BluetoothChatService";   
  39.     private static final boolean D = true;   
  40.     // Name for the SDP record when creating server socket   
  41.     private static final String NAME = "BluetoothChat";   
  42.     // Unique UUID for this application   
  43.     private static final UUID MY_UUID = UUID.fromString("fa87c0d0-afac-11de-8a39-0800200c9a66");   
  44.     // Member fields   
  45.     private final BluetoothAdapter mAdapter;   
  46.     private final Handler mHandler;   
  47.     private AcceptThread mAcceptThread;   
  48.     private ConnectThread mConnectThread;   
  49.     private ConnectedThread mConnectedThread;   
  50.     private int mState;   
  51.     // Constants that indicate the current connection state   
  52.     public static final int STATE_NONE = 0;       // we're doing nothing   
  53.     public static final int STATE_LISTEN = 1;     // now listening for incoming connections   
  54.     public static final int STATE_CONNECTING = 2// now initiating an outgoing connection   
  55.     public static final int STATE_CONNECTED = 3;  // now connected to a remote device   
  56.     /**  
  57.      * Constructor. Prepares a new BluetoothChat session.  
  58.      * @param context  The UI Activity Context  
  59.      * @param handler  A Handler to send messages back to the UI Activity  
  60.      */  
  61.     public BluetoothChatService(Context context, Handler handler) {   
  62.         mAdapter = BluetoothAdapter.getDefaultAdapter();   
  63.         mState = STATE_NONE;   
  64.         mHandler = handler;   
  65.     }   
  66.     /**  
  67.      * Set the current state of the chat connection  
  68.      * @param state  An integer defining the current connection state  
  69.      */  
  70.     private synchronized void setState(int state) {   
  71.         if (D) Log.d(TAG, "setState() " + mState + " -> " + state);   
  72.         mState = state;   
  73.         // Give the new state to the Handler so the UI Activity can update 更新狀態,使用Handler向UI發送消息提示   
  74.         mHandler.obtainMessage(BluetoothChat.MESSAGE_STATE_CHANGE, state, -1).sendToTarget();   
  75.     }   
  76.     /**  
  77.      * Return the current connection state. */  
  78.     public synchronized int getState() {   
  79.         return mState;   
  80.     }   
  81.     /**  
  82.      * Start the chat service. Specifically start AcceptThread to begin a  
  83.      * session in listening (server) mode. Called by the Activity onResume() */  
  84.     public synchronized void start() {   
  85.         if (D) Log.d(TAG, "start");   
  86.         // Cancel any thread attempting to make a connection   
  87.         if (mConnectThread != null) {mConnectThread.cancel(); mConnectThread = null;}   
  88.         // Cancel any thread currently running a connection   
  89.         if (mConnectedThread != null) {mConnectedThread.cancel(); mConnectedThread = null;}   
  90.         // Start the thread to listen on a BluetoothServerSocket   
  91.         if (mAcceptThread == null) {   
  92.             mAcceptThread = new AcceptThread();   
  93.             mAcceptThread.start();   
  94.         }   
  95.         setState(STATE_LISTEN);   
  96.     }   
  97.     /**  
  98.      * Start the ConnectThread to initiate a connection to a remote device.  
  99.      * @param device  The BluetoothDevice to connect  
  100.      */  
  101.     public synchronized void connect(BluetoothDevice device) {   
  102.         if (D) Log.d(TAG, "connect to: " + device);   
  103.         // Cancel any thread attempting to make a connection   
  104.         if (mState == STATE_CONNECTING) {   
  105.             if (mConnectThread != null) {mConnectThread.cancel(); mConnectThread = null;}   
  106.         }   
  107.         // Cancel any thread currently running a connection   
  108.         if (mConnectedThread != null) {mConnectedThread.cancel(); mConnectedThread = null;}   
  109.         // Start the thread to connect with the given device 設置正在狀態為正在連接   
  110.         mConnectThread = new ConnectThread(device);   
  111.         mConnectThread.start();   
  112.         setState(STATE_CONNECTING);   
  113.     }   
  114.     /**  
  115.      * Start the ConnectedThread to begin managing a Bluetooth connection  
  116.      * @param socket  The BluetoothSocket on which the connection was made  
  117.      * @param device  The BluetoothDevice that has been connected  
  118.      */  
  119.     public synchronized void connected(BluetoothSocket socket, BluetoothDevice device) {   
  120.         if (D) Log.d(TAG, "connected");   
  121.         // Cancel the thread that completed the connection   
  122.         if (mConnectThread != null) {mConnectThread.cancel(); mConnectThread = null;}   
  123.         // Cancel any thread currently running a connection   
  124.         if (mConnectedThread != null) {mConnectedThread.cancel(); mConnectedThread = null;}   
  125.         // Cancel the accept thread because we only want to connect to one device   
  126.         if (mAcceptThread != null) {mAcceptThread.cancel(); mAcceptThread = null;}   
  127.         // Start the thread to manage the connection and perform transmissions   
  128.         mConnectedThread = new ConnectedThread(socket);   
  129.         mConnectedThread.start();   
  130.         // Send the name of the connected device back to the UI Activity   
  131.         Message msg = mHandler.obtainMessage(BluetoothChat.MESSAGE_DEVICE_NAME);   
  132.         Bundle bundle = new Bundle();   
  133.         bundle.putString(BluetoothChat.DEVICE_NAME, device.getName());   
  134.         msg.setData(bundle);   
  135.         mHandler.sendMessage(msg);   
  136.         setState(STATE_CONNECTED);   
  137.     }   
  138.     /**  
  139.      * Stop all threads  
  140.      */  
  141.     public synchronized void stop() {   
  142.         if (D) Log.d(TAG, "stop");   
  143.         if (mConnectThread != null) {mConnectThread.cancel(); mConnectThread = null;}   
  144.         if (mConnectedThread != null) {mConnectedThread.cancel(); mConnectedThread = null;}   
  145.         if (mAcceptThread != null) {mAcceptThread.cancel(); mAcceptThread = null;}   
  146.         setState(STATE_NONE);   
  147.     }   
  148.     /**  
  149.      * Write to the ConnectedThread in an unsynchronized manner  
  150.      * @param out The bytes to write  
  151.      * @see ConnectedThread#write(byte[])  
  152.      */  
  153.     public void write(byte[] out) {   
  154.         // Create temporary object   
  155.         ConnectedThread r;   
  156.         // Synchronize a copy of the ConnectedThread   
  157.         synchronized (this) {   
  158.             if (mState != STATE_CONNECTED) return;   
  159.             r = mConnectedThread;   
  160.         }   
  161.         // Perform the write unsynchronized   
  162.         r.write(out);   
  163.     }   
  164.     /**  
  165.      * Indicate that the connection attempt failed and notify the UI Activity.  
  166.      */  
  167.     private void connectionFailed() {   
  168.         setState(STATE_LISTEN);   
  169.         // Send a failure message back to the Activity更新狀態,使用Handler向UI發送消息提示   
  170.         Message msg = mHandler.obtainMessage(BluetoothChat.MESSAGE_TOAST);   
  171.         Bundle bundle = new Bundle();   
  172.         bundle.putString(BluetoothChat.TOAST, "Unable to connect device");   
  173.         msg.setData(bundle);   
  174.         mHandler.sendMessage(msg);   
  175.     }   
  176.     /**  
  177.      * Indicate that the connection was lost and notify the UI Activity.  
  178.      */  
  179.     private void connectionLost() {   
  180.         setState(STATE_LISTEN);   
  181.         // Send a failure message back to the Activity更新狀態,使用Handler向UI發送消息提示   
  182.         Message msg = mHandler.obtainMessage(BluetoothChat.MESSAGE_TOAST);   
  183.         Bundle bundle = new Bundle();   
  184.         bundle.putString(BluetoothChat.TOAST, "Device connection was lost");   
  185.         msg.setData(bundle);   
  186.         mHandler.sendMessage(msg);   
  187.     }   
  188.     /**  
  189.      * This thread runs while listening for incoming connections. It behaves  
  190.      * like a server-side client. It runs until a connection is accepted  
  191.      * (or until cancelled).  
  192.      */  
  193.     private class AcceptThread extends Thread {   
  194.         // The local server socket   
  195.         private final BluetoothServerSocket mmServerSocket;   
  196.         public AcceptThread() {   
  197.             BluetoothServerSocket tmp = null;   
  198.             // Create a new listening server socket   
  199.             try {   
  200.                 tmp = mAdapter.listenUsingRfcommWithServiceRecord(NAME, MY_UUID);   
  201.             } catch (IOException e) {   
  202.                 Log.e(TAG, "listen() failed", e);   
  203.             }   
  204.             mmServerSocket = tmp;   
  205.         }   
  206.         public void run() {   
  207.             if (D) Log.d(TAG, "BEGIN mAcceptThread" + this);   
  208.             setName("AcceptThread");   
  209.             BluetoothSocket socket = null;   
  210.             // Listen to the server socket if we're not connected 不斷監聽是否有藍牙連接請求   
  211.             while (mState != STATE_CONNECTED) {    
  212.                 try {   
  213.                     // This is a blocking call and will only return on a   
  214.                     // successful connection or an exception   
  215.                     socket = mmServerSocket.accept();   
  216.                 } catch (IOException e) {   
  217.                     Log.e(TAG, "accept() failed", e);   
  218.                     break;   
  219.                 }   
  220.                 // If a connection was accepted   
  221.                 if (socket != null) {   
  222.                     synchronized (BluetoothChatService.this) {   
  223.                         switch (mState) {   
  224.                         case STATE_LISTEN:   
  225.                         case STATE_CONNECTING:   
  226.                             // Situation normal. Start the connected thread. 當有連接請求且狀態是正在連接時   
  227.                             connected(socket, socket.getRemoteDevice());   
  228.                             break;   
  229.                         case STATE_NONE:   
  230.                         case STATE_CONNECTED:   
  231.                             // Either not ready or already connected. Terminate new socket.   
  232.                             try {   
  233.                                 socket.close();   
  234.                             } catch (IOException e) {   
  235.                                 Log.e(TAG, "Could not close unwanted socket", e);   
  236.                             }   
  237.                             break;   
  238.                         }   
  239.                     }   
  240.                 }   
  241.             }   
  242.             if (D) Log.i(TAG, "END mAcceptThread");   
  243.         }   
  244.         public void cancel() {   
  245.             if (D) Log.d(TAG, "cancel " + this);   
  246.             try {   
  247.                 mmServerSocket.close();   
  248.             } catch (IOException e) {   
  249.                 Log.e(TAG, "close() of server failed", e);   
  250.             }   
  251.         }   
  252.     }   
  253.   
  254.     /**  
  255.      * This thread runs while attempting to make an outgoing connection  
  256.      * with a device. It runs straight through; the connection either  
  257.      * succeeds or fails.  
  258.      */  
  259.     private class ConnectThread extends Thread {   
  260.         private final BluetoothSocket mmSocket;   
  261.         private final BluetoothDevice mmDevice;   
  262.         public ConnectThread(BluetoothDevice device) {   
  263.             mmDevice = device;   
  264.             BluetoothSocket tmp = null;   
  265.             // Get a BluetoothSocket for a connection with the   
  266.             // given BluetoothDevice   
  267.             try {   
  268.                 tmp = device.createRfcommSocketToServiceRecord(MY_UUID);   
  269.             } catch (IOException e) {   
  270.                 Log.e(TAG, "create() failed", e);   
  271.             }   
  272.             mmSocket = tmp;   
  273.         }   
  274.         public void run() {   
  275.             Log.i(TAG, "BEGIN mConnectThread");   
  276.             setName("ConnectThread");   
  277.             // Always cancel discovery because it will slow down a connection   
  278.             mAdapter.cancelDiscovery();   
  279.             // Make a connection to the BluetoothSocket   
  280.             try {   
  281.                 // This is a blocking call and will only return on a   
  282.                 // successful connection or an exception   
  283.                 mmSocket.connect();   
  284.             } catch (IOException e) {   
  285.                 connectionFailed();   
  286.                 // Close the socket   
  287.                 try {   
  288.                     mmSocket.close();   
  289.                 } catch (IOException e2) {   
  290.                     Log.e(TAG, "unable to close() socket during connection failure", e2);   
  291.                 }   
  292.                 // Start the service over to restart listening mode   
  293.                 BluetoothChatService.this.start();   
  294.                 return;   
  295.             }   
  296.             // Reset the ConnectThread because we're done   
  297.             synchronized (BluetoothChatService.this) {   
  298.                 mConnectThread = null;   
  299.             }   
  300.             // Start the connected thread   
  301.             connected(mmSocket, mmDevice);   
  302.         }   
  303.         public void cancel() {   
  304.             try {   
  305.                 mmSocket.close();   
  306.             } catch (IOException e) {   
  307.                 Log.e(TAG, "close() of connect socket failed", e);   
  308.             }   
  309.         }   
  310.     }   
  311.     /**  
  312.      * This thread runs during a connection with a remote device.  
  313.      * It handles all incoming and outgoing transmissions.  
  314.      */  
  315.     private class ConnectedThread extends Thread {   
  316.         private final BluetoothSocket mmSocket;   
  317.         private final InputStream mmInStream;   
  318.         private final OutputStream mmOutStream;   
  319.         public ConnectedThread(BluetoothSocket socket) {   
  320.             Log.d(TAG, "create ConnectedThread");   
  321.             mmSocket = socket;   
  322.             InputStream tmpIn = null;   
  323.             OutputStream tmpOut = null;   
  324.             // Get the BluetoothSocket input and output streams   
  325.             try {   
  326.                 tmpIn = socket.getInputStream();   
  327.                 tmpOut = socket.getOutputStream();   
  328.             } catch (IOException e) {   
  329.                 Log.e(TAG, "temp sockets not created", e);   
  330.             }   
  331.             mmInStream = tmpIn;   
  332.             mmOutStream = tmpOut;   
  333.         }   
  334.         public void run() {   
  335.             Log.i(TAG, "BEGIN mConnectedThread");   
  336.             byte[] buffer = new byte[1024];   
  337.             int bytes;   
  338.             // Keep listening to the InputStream while connected   
  339.             while (true) {   
  340.                 try {   
  341.                     // Read from the InputStream    
  342.                     bytes = mmInStream.read(buffer);   
  343.                     // Send the obtained bytes to the UI Activity   
  344.                     mHandler.obtainMessage(BluetoothChat.MESSAGE_READ, bytes, -1, buffer)   
  345.                             .sendToTarget();   
  346.                 } catch (IOException e) {   
  347.                     Log.e(TAG, "disconnected", e);   
  348.                     connectionLost();   
  349.                     break;   
  350.                 }   
  351.             }   
  352.         }   
  353.         /**  
  354.          * Write to the connected OutStream.  
  355.          * @param buffer  The bytes to write  
  356.          */  
  357.         public void write(byte[] buffer) {   
  358.             try {   
  359.                 mmOutStream.write(buffer); //向對方寫數據   
  360.                 // Share the sent message back to the UI Activity   
  361.                 mHandler.obtainMessage(BluetoothChat.MESSAGE_WRITE, -1, -1, buffer)   
  362.                         .sendToTarget();   
  363.             } catch (IOException e) {   
  364.                 Log.e(TAG, "Exception during write", e);   
  365.             }   
  366.         }   
  367.         public void cancel() {   
  368.             try {   
  369.                 mmSocket.close();   
  370.             } catch (IOException e) {   
  371.                 Log.e(TAG, "close() of connect socket failed", e);   
  372.             }   
  373.         }   
  374.     }   
  375. }  

里面的難點就是BluetoothChatService.java這個類中幾個線程的理解;

ConnectThread這個線程就是連接socket的線程.如果斷開就執行 BluetoothChatService.this.start();這段句代碼來重新獲取socket

那么AcceptThread這個就很容易理解了.就是獲取socket的線程.

ConnectedThread這個線程就是一直運行着來接受輸入輸出數據的線程.當ConnectThread連接之后就開始執行他.

其他的都比較好理解吧

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM