2010-07-07 151 views
3

我需要將我的android連接到藍牙設備。我使用Google的BluetoothChat示例。如何斷開藍牙連接(HTC Desire)

我在使用Google Nexus之一時遇到了一些麻煩,因爲Nexus正在進行連接,但之後立即斷開連接。我需要啓動兩次連接作爲解決方法(請參閱connectionLost())。

現在,它在Nexus One和HTC Desire上運行良好。

我的問題是應用程序退出時的斷開連接。它在Nexus One上正常工作,連接已關閉,但不在HTC Desire上。除了套接字關閉之外,我還添加了inputstream/outputstream關閉函數。看看「stop()」函數。

package xxx.yyy.zzz; 

import java.io.IOException; 
import java.io.InputStream; 
import java.io.OutputStream; 
import java.lang.reflect.Method; 
import java.util.UUID; 

import activities.Act_Main; 

import android.bluetooth.BluetoothAdapter; 
import android.bluetooth.BluetoothDevice; 
import android.bluetooth.BluetoothSocket; 
import android.content.Context; 
import android.os.Bundle; 
import android.os.Handler; 
import android.os.Message; 
import android.util.Log; 

/** 
* This class does all the work for setting up and managing Bluetooth 
* connections with other devices. It has a thread that listens for 
* incoming connections, a thread for connecting with a device, and a 
* thread for performing data transmissions when connected. 
*/ 
public class BluetoothService { 
    // Debugging 
    private static final String TAG = "BluetoothService"; 
    private static final boolean D = true; 

    // Member fields 
    //private final BluetoothAdapter mAdapter; 
    private final Handler mHandler; 
    private ConnectThread mConnectThread; 
    private ConnectedThread mConnectedThread; 
    private int mState; 
    private String mBTAddress; 
    private boolean isStop = false; 

    // Constants that indicate the current connection state 
    public static final int STATE_NONE = 0;  // we're doing nothing 
    public static final int STATE_LISTEN = 1;  // now listening for incoming connections 
    public static final int STATE_CONNECTING = 2; // now initiating an outgoing connection 
    public static final int STATE_CONNECTED = 3; // now connected to a remote device 

    /** 
    * Constructor. Prepares a new Act_Main session. 
    * @param context The UI Activity Context 
    * @param handler A Handler to send messages back to the UI Activity 
    */ 
    public BluetoothService(Context context, Handler handler) 
    { 
     //mAdapter = BluetoothAdapter.getDefaultAdapter(); 
     mState = STATE_NONE; 
     mHandler = handler; 
    } 

    /** 
    * Set the current state of the connection 
    * @param state An integer defining the current connection state 
    */ 
    private synchronized void setState(int state) 
    { 
     if (D) Log.d(TAG, "setState() " + mState + " -> " + state); 
     mState = state; 

     // Give the new state to the Handler so the UI Activity can update 
     mHandler.obtainMessage(Act_Main.MESSAGE_STATE_CHANGE, state, -1).sendToTarget(); 
    } 

    /** 
    * Return the current connection state. */ 
    public synchronized int getState() 
    { 
     return mState; 
    } 

    /** 
    * Start the ConnectThread to initiate a connection to a remote device. 
    * @param device The BluetoothDevice to connect 
    */ 
    public synchronized void connect(String BTAddress) 
    { 
     mBTAddress = BTAddress ; 

     // Get the BLuetoothDevice object 
     BluetoothDevice device = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(BTAddress); 

     if (D) Log.d(TAG, "connect to: " + device); 

     // Cancel any thread attempting to make a connection 
     if (mState == STATE_CONNECTING) 
      if (mConnectThread != null) {mConnectThread.cancel(); mConnectThread = null;} 

     // Cancel any thread currently running a connection 
     if (mConnectedThread != null) {mConnectedThread.cancel(); mConnectedThread = null;} 

     // Start the thread to connect with the given device 
     mConnectThread = new ConnectThread(device); 
     mConnectThread.start(); 
     setState(STATE_CONNECTING); 
     isStop = false ; 
    } 

    /** 
    * Start the ConnectedThread to begin managing a Bluetooth connection 
    * @param socket The BluetoothSocket on which the connection was made 
    * @param device The BluetoothDevice that has been connected 
    */ 
    public synchronized void connected(BluetoothSocket socket, BluetoothDevice device) 
    { 
     if (D) Log.d(TAG, "connected"); 

     // Cancel the thread that completed the connection 
     if (mConnectThread != null) {mConnectThread.cancel(); mConnectThread = null;} 

     // Cancel any thread currently running a connection 
     if (mConnectedThread != null) {mConnectedThread.cancel(); mConnectedThread = null;} 

     // Start the thread to manage the connection and perform transmissions 
     mConnectedThread = new ConnectedThread(socket); 
     mConnectedThread.start(); 

     // Send the name of the connected device back to the UI Activity 
     Message msg = mHandler.obtainMessage(Act_Main.MESSAGE_DEVICE_NAME); 
     Bundle bundle = new Bundle(); 
     bundle.putString(Act_Main.DEVICE_NAME, device.getName()); 
     msg.setData(bundle); 
     mHandler.sendMessage(msg); 

     setState(STATE_CONNECTED); 
    } 

    /** 
    * Stop all threads 
    */ 
    public synchronized void stop() 
    { 
     isStop = true ; 

     if (D) 
      Log.d(TAG, "stop"); 

     if(mConnectThread != null) 
     { 
      mConnectThread.cancel(); 
      Thread moribund = mConnectThread; 
      mConnectThread = null; 
      moribund.interrupt(); 
     } 

     if(mConnectedThread != null) 
     { 
      mConnectedThread.cancel(); 
      Thread moribund = mConnectedThread; 
      mConnectedThread = null; 
      moribund.interrupt(); 
     } 

     setState(STATE_NONE); 
    } 

    /** 
    * Write to the ConnectedThread in an unsynchronized manner 
    * @param out The bytes to write 
    * @see ConnectedThread#write(byte[]) 
    */ 
    public void write(byte[] out) 
    { 
     // Create temporary object 
     ConnectedThread r; 

     // Synchronize a copy of the ConnectedThread 
     synchronized (this) 
     { 
      Log.d(TAG, "BT_SEND_MESSAGE"); 

      if (mState != STATE_CONNECTED) 
       return; 

      r = mConnectedThread; 
     } 

     // Perform the write unsynchronized 
     r.write(out); 
    } 

    /** 
    * Indicate that the connection attempt failed and notify the UI Activity. 
    */ 
    private void connectionFailed() 
    { 
     try 
     { 
      synchronized (this) 
      { 
       this.wait(3000); 
      } 
      connect(mBTAddress); 
     } 
     catch(InterruptedException ex) 
     { 
      Log.e(TAG, "WAIT_EXCEPTION:"+ ex.getMessage()); 
     } 
    } 

    /** 
    * Indicate that the connection was lost and notify the UI Activity. 
    */ 
    private void connectionLost() 
    { 
     if (!isStop) 
      connect(mBTAddress); 
    } 

    /** 
    * This thread runs while attempting to make an outgoing connection 
    * with a device. It runs straight through; the connection either 
    * succeeds or fails. 
    */ 
    private class ConnectThread extends Thread 
    { 
     private final BluetoothSocket mmSocket; 
     private final BluetoothDevice mmDevice; 

     public ConnectThread(BluetoothDevice device) 
     { 
      mmDevice = device; 
      BluetoothSocket tmp = null; 

      // Get a BluetoothSocket for a connection with the 
      // given BluetoothDevice 
      try 
      { 
       tmp = device.createRfcommSocketToServiceRecord(UUID.fromString("00001101-0000-1000-8000-00805F9B34FB")); 
      } 
      catch (Exception e) 
      { 
       Log.e(TAG, "create() failed", e); 
      } 
      mmSocket = tmp; 
     } 

     public void run() 
     { 
      Log.i(TAG, "BEGIN mConnectThread"); 
      setName("ConnectThread"); 

      // Always cancel discovery because it will slow down a connection 
      //mAdapter.cancelDiscovery(); 

      // Make a connection to the BluetoothSocket 
      try 
      { 
       // This is a blocking call and will only return on a successful connection or an exception 
       mmSocket.connect(); 
      } 
      catch (IOException e) 
      { 
       connectionFailed(); 

       // Close the socket 
       try 
       { 
        mmSocket.close(); 
       } 
       catch (IOException e2) 
       { 
        Log.e(TAG, "unable to close() socket during connection failure", e2); 
       } 
       return; 
      } 

      // Reset the ConnectThread because we're done 
      synchronized (BluetoothService.this) 
      { 
       mConnectThread = null; 
      } 

      // Start the connected thread 
      connected(mmSocket, mmDevice); 
     } 

     public void cancel() 
     { 
      try 
      { 
       mmSocket.close(); 
      } 
      catch (IOException e) 
      { 
       Log.e(TAG, "close() of connect socket failed", e); 
      } 
     } 
    } 

    /** 
    * This thread runs during a connection with a remote device. 
    * It handles all incoming and outgoing transmissions. 
    */ 
    private class ConnectedThread extends Thread { 
     private BluetoothSocket mmSocket; 
     private InputStream mmInStream; 
     private OutputStream mmOutStream; 

     public ConnectedThread(BluetoothSocket socket) { 
      Log.d(TAG, "create ConnectedThread"); 
      mmSocket = socket; 
      InputStream tmpIn = null; 
      OutputStream tmpOut = null; 

      // Get the BluetoothSocket input and output streams 
      try { 
       tmpIn = socket.getInputStream(); 
       tmpOut = socket.getOutputStream(); 
      } catch (IOException e) { 
       Log.e(TAG, "temp sockets not created", e); 
      } 

      mmInStream = tmpIn; 
      mmOutStream = tmpOut; 
     } 

     public void run() 
     { 
      Log.i(TAG, "BEGIN mConnectedThread"); 
      byte[] buffer; 
      int bytes = 0; 

      // Keep listening to the InputStream while connected 
      while (true) 
      { 
       try 
       { 
        //Clear buffer 
        buffer = new byte[1024]; 

        // Read from the InputStream 
        bytes = mmInStream.read(buffer); 

        // Send the obtained bytes to the UI Activity 
        mHandler.obtainMessage(Act_Main.MESSAGE_READ, bytes, -1, buffer).sendToTarget(); 
       } 
       catch (IOException e) 
       { 
        //String bufferStr = new String(buffer, 0, buffer.length); 
        Log.e(TAG, "disconnected", e); 
        connectionLost(); 
        break; 
       } 
      } 
     } 

     /** 
     * Write to the connected OutStream. 
     * @param buffer The bytes to write 
     */ 
     public void write(byte[] buffer) 
     { 
      try 
      { 
       mmOutStream.write(buffer); 
      } 
      catch (IOException e) 
      { 
       Log.e(TAG, "Exception during write", e); 
      } 
     } 

     public void cancel() 
     { 
      if (mmOutStream != null) 
      { 
       try {mmOutStream.close();} catch (Exception e) { Log.e(TAG, "close() of outputstream failed", e); } 
       mmOutStream = null; 
      } 

      if (mmInStream != null) 
      { 
       try {mmInStream.close();} catch (Exception e) { Log.e(TAG, "close() of inputstream failed", e); } 
       mmInStream = null; 
      } 

      if (mmSocket != null) 
      { 
       try {mmSocket.close();} catch (Exception e) { Log.e(TAG, "close() of connect socket failed", e); } 
       mmSocket = null; 
      } 
     } 
    } 
} 

在此先感謝您的幫助。

JJ

+0

人這個例子,我從谷歌討厭它的一切都在連接時讀取數據流,你不應該這樣做。使用一段時間(真)是我厭惡的東西。我總是使用while(!Thread.interrupted()) – JPM 2011-10-27 15:44:53

回答

1

你的代碼中的同步快速評論:

留下你的connect()方法​​關鍵字,但是當談到時間來連接,從一個線程調用你的connect(),而不是從你的connect()創建線程。就目前而言,您的代碼正在觸發connect()的連接線程,並破壞了同步的目的。 (目的是將請求同步到connect(),以便多個線程不會混亂,因爲他們同時嘗試到connect)。這可能會導致一些連接問題。

關於HTC:

我覺得你和我遇到了同樣的問題:Why can't HTC Droid running OTA 2.1 communicate with RFCOMM?

有關斷開藍牙連接注:

確保每一次正常斷開使用您的cancel()方法。

+0

感謝您的同步解釋。谷歌提供的源代碼...這很令人驚訝。 HTC的藍牙問題也很瘋狂......如果您有任何關於HTC的消息,請告知我。 – Hrk 2010-07-08 11:55:52

0

我剛剛看了這篇文章現在:Bluetooth on 2.0+

有沒有人的壞實施的HTC Desire的解決方案?

更新:例如,我做了一個非常糟糕的解決方法。當我退出應用程序時,我終止了進程:

ActivityManager am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE); 
am.restartPackage("com.example.package"); 

我還在等待更清潔的解決方案。

0

更新:看來HTC固定的,通過他們的Froyo更新版本(Android 2.2)