2010-06-13 19 views
39

Estoy desarrollando un programa en el que, desde un teléfono Android, tengo que conectarme como cliente a un sensor médico Bluetooth. Estoy usando la API oficial de Bluetooth y no hay problema durante la conexión (perfil SPP), pero cuando termino el socket, el sensor todavía está conectado a mi teléfono (aunque tengo cerrada la conexión).Desconectar un conector bluetooth en Android

¿Hay alguna forma de realizar una desconexión de Bluetooth? Creo que hay una intención llamada ACTION_ACL_CONNECTED, que hace eso. ¿Alguien puede explicarme cómo usar esto?

Gracias de antemano.

EDITADO: Aquí está el código, si alguien necesita información adicional, es un sensor médico Nonin 4100.

Set<BluetoothDevice> pairedDevices = Activa.myBluetoothAdapter.getBondedDevices(); 
     // If there are paired devices 
     if (pairedDevices.size() > 0) { 
      // Loop through paired devices 
      for (BluetoothDevice device : pairedDevices) { 
       // Add the name and address to an array adapter to show in a ListView 
       String name = device.getName(); 
       if (name.contains("Nonin")) { 
        try { 
         found = true; 
//      socket = device.createRfcommSocketToServiceRecord(UUID.fromString("00001101-0000-1000-8000-00805F9B34FB")); 
//      handler.sendEmptyMessage(5); 
//      Activa.myBluetoothAdapter.cancelDiscovery(); 
//      socket.connect(); 
         BluetoothDevice hxm = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(device.getAddress()); 
         Method m; 
         try { 
          m = hxm.getClass().getMethod("createRfcommSocket", new Class[]{int.class}); 
          socket = (BluetoothSocket)m.invoke(hxm, Integer.valueOf(1)); 
          handler.sendEmptyMessage(5); 
          socket.connect(); 
         } catch (Exception e) { 
          handler.sendEmptyMessage(7); 
          e.printStackTrace(); 
          break; 
         } 
         handler.sendEmptyMessage(6); 
         InputStream in = socket.getInputStream(); 
         OutputStream out = socket.getOutputStream(); 
         byte[] retrieve = { 0x44, 0x31}; 
         out.write(retrieve); 
         byte [] ack = new byte [1]; 
         in.read(ack); 
         if (ack[0] == 0x15) { 
          cancelMeasurement(); 
          return; 
         } 
         byte [] data = new byte [3]; 
         long timeStart = System.currentTimeMillis(); 
         this.timePassed = System.currentTimeMillis() - timeStart; 
         while ((this.timePassed < (this.time))&&(this.finished)) { 
          try { 
           in.read(data); 
           processData(data); 
           Thread.sleep(1000); 
           this.timePassed = System.currentTimeMillis() - timeStart; 
          } catch (Exception e) { 
           e.printStackTrace(); 
          } 
         } 
         in.close(); 
         out.close(); 
         socket.close(); 
        } catch (IOException e) { 
         e.printStackTrace(); 
        } 
       } 
      } 
     } 
} 

Respuesta

58

Recuerde cerrar primero los flujos de entrada/salida, luego cierre el zócalo.

Al cerrar las transmisiones, se inicia el proceso de desconexión. Después de cerrar el socket, la conexión debe estar completamente desglosada.

Si cierra el socket antes de las transmisiones, es posible que esté pasando por alto ciertos pasos de apagado, como el cierre (correcto) de la conexión de la capa física.

Este es el método que uso cuando llega el momento de averiar la conexión.

/** 
* Reset input and output streams and make sure socket is closed. 
* This method will be used during shutdown() to ensure that the connection is properly closed during a shutdown. 
* @return 
*/ 
private void resetConnection() { 
     if (mBTInputStream != null) { 
       try {mBTInputStream.close();} catch (Exception e) {} 
       mBTInputStream = null; 
     } 

     if (mBTOutputStream != null) { 
       try {mBTOutputStream.close();} catch (Exception e) {} 
       mBTOutputStream = null; 
     } 

     if (mBTSocket != null) { 
       try {mBTSocket.close();} catch (Exception e) {} 
       mBTSocket = null; 
     } 

} 

EDIT: Adición de código para connect():

// bluetooth adapter which provides access to bluetooth functionality. 
BluetoothAdapter  mBTAdapter  = null; 
// socket represents the open connection. 
BluetoothSocket   mBTSocket = null; 
// device represents the peer 
BluetoothDevice   mBTDevice  = null; 

// streams 
InputStream   mBTInputStream = null; 
OutputStream   mBTOutputStream = null; 

static final UUID UUID_RFCOMM_GENERIC = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"); 

/** 
* Try to establish a connection with the peer. 
* This method runs synchronously and blocks for one or more seconds while it does its thing 
* SO CALL IT FROM A NON-UI THREAD! 
* @return - returns true if the connection has been established and is ready for use. False otherwise. 
*/ 
private boolean connect() { 

     // Reset all streams and socket. 
     resetConnection(); 

     // make sure peer is defined as a valid device based on their MAC. If not then do it. 
     if (mBTDevice == null) 
       mBTDevice = mBTAdapter.getRemoteDevice(mPeerMAC); 

     // Make an RFCOMM binding. 
     try {mBTSocket = mBTDevice.createRfcommSocketToServiceRecord(UUID_RFCOMM_GENERIC); 
     } catch (Exception e1) { 
       msg ("connect(): Failed to bind to RFCOMM by UUID. msg=" + e1.getMessage()); 
       return false; 
     } 

     msg ("connect(): Trying to connect."); 

     try { 
       mBTSocket.connect(); 
     } catch (Exception e) { 
       msg ("connect(): Exception thrown during connect: " + e.getMessage()); 
       return false; 
     } 

     msg ("connect(): CONNECTED!"); 

     try { 
       mBTOutputStream = mBTSocket.getOutputStream(); 
       mBTInputStream = mBTSocket.getInputStream(); 
     } catch (Exception e) { 
       msg ("connect(): Error attaching i/o streams to socket. msg=" + e.getMessage()); 
       return false; 
     } 

     return true; 
} 
+1

Hola, En primer lugar, thansk por su respuesta, pero no me resuelve el problema. Estaba haciendo algo similar (es decir, primero cerrando las transmisiones y luego el socket) y desconecto la conexión del lado de Android, pero el sensor médico que estaba usando no se anuncia de la desconexión y continúa conectado, entonces puedo volveré a conectarlo a menos que lo reinicie. – user365610

+0

Por favor, publique su código. En este punto, solo estamos adivinando. He visto el problema que estás informando, pero puede haber muchas causas, así que antes de perder más de mi tiempo adivinando, publica tu código. –

+0

He editado la publicación original con el código. He reemplazado la parte de cerrar las transmisiones y el socket con la que me pasaste, pero sigue siendo igual. Gracias por adelantado. – user365610

9

HI,

he visto el mismo problema (HTC Desire). A pesar de cerrar el socket por el libro (como sugiere Brad), el siguiente connect() bloquea para siempre, hasta que termina por close() por otro hilo.

Evité el problema llamando siempre a BluetoothAdapter.disable() /. Enable() antes de conectar. Horrible, antipático hack, lo sé ...

Sospecho que algunos de los problemas actuales de BT son específicos del fabricante, ya que algunos implementadores de aplicaciones parecen vivir felices con createRfcommSocketToServiceRecord(), que definitivamente falla en mi HTC Desire (Android 2.1 actualización 1).

He visto indicaciones (lo siento, no tengo referencias) de que la pila BT de HTC Desire difiere de la Nexus One, aunque parecen ser dispositivos muy similares ...

BR por

(adición) Aquí es una actividad muy sencilla para reproducir el problema (sin mi 'cura' activar/desactivar):

package com.care2wear.BtTest; 

import java.io.IOException; 
import java.io.InputStream; 
import java.io.OutputStream; 
import java.lang.reflect.InvocationTargetException; 
import java.lang.reflect.Method; 

import android.app.Activity; 
import android.bluetooth.BluetoothAdapter; 
import android.bluetooth.BluetoothDevice; 
import android.bluetooth.BluetoothSocket; 
import android.os.Bundle; 
import android.util.Log; 
import android.widget.TextView; 

public class BtTestActivity extends Activity { 
    private static final String TAG="BtTest"; 

    BluetoothAdapter mBtAdapter = null; 
    BluetoothDevice mBtDev = null; 
    BluetoothSocket mBtSocket = null; 
    InputStream isBt; 
    OutputStream osBt; 
    String mAddress = "00:18:E4:1C:A4:66"; 

    /** Called when the activity is first created. */ 
    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.main); 


     init(); 

     connect(); // ok 
     disconnect(); // ok 
     connect(); // this invariably fails - blocked until BT is switched off by someone else, or the peer device turns off/goes out of range 
     disconnect(); 
    } 

    private void init() { 
     Log.d(TAG, "initializing"); 
     mBtAdapter = BluetoothAdapter.getDefaultAdapter(); 
     mBtDev = mBtAdapter.getRemoteDevice(mAddress); 
     Log.d(TAG, "initialized"); 
    } 

    private void connect() { 
     try { 
      Log.d(TAG, "connecting"); 
      Method m = mBtDev.getClass().getMethod("createRfcommSocket", new Class[] { int.class }); 
      mBtSocket = (BluetoothSocket) m.invoke(mBtDev, 1); 
      mBtSocket.connect(); 
      Log.d(TAG, "connected"); 
     } catch (SecurityException e) { 
      Log.e(TAG, "SecEx", e); 
     } catch (NoSuchMethodException e) { 
      Log.e(TAG, "NsmEx", e); 
     } catch (IllegalArgumentException e) { 
      Log.e(TAG, "IArgEx", e); 
     } catch (IllegalAccessException e) { 
      Log.e(TAG, "IAccEx", e); 
     } catch (InvocationTargetException e) { 
      Log.e(TAG, "ItEx", e); 
     } catch (IOException e) { 
      Log.e(TAG, "IOEx", e); 
     } 

    } 

    private void disconnect() { 
     Log.d(TAG, "closing"); 

     if (isBt != null) { 
      try { 
       isBt.close(); 
      } catch (IOException e) { 
       Log.e(TAG, "isBt IOE", e);    
      } 
      isBt = null; 
     } 
     if (osBt != null) { 
      try { 
       osBt.close(); 
      } catch (IOException e) { 
       Log.e(TAG, "osBt IOE", e);    
      } 
      osBt = null; 
     } 
     if (mBtSocket != null) { 
      try { 
       mBtSocket.close(); 
      } catch (IOException e) { 
       Log.e(TAG, "socket IOE", e);     
      } 
      mBtSocket = null; 
     } 
     Log.d(TAG, "closed");  
    } 
} 

Si alguien puede detectar si lo estoy haciendo mal, no dude en comentar :)

(adición 2) Creo que tengo que funcione ahora:

  1. El método oficial de la conexión RFCOMM (a través de SDP) ahora en realidad parece funcionar (HTC Desire, 2.1 Update 1), PERO tuve que quitar y volver a acoplar el dispositivo BT. Ve figura ...
  2. La reconexión puede seguir fallando (falla en el descubrimiento del servicio) si me vuelvo a conectar 'demasiado rápido' (salgo de la aplicación, y luego reinicio de inmediato). Supongo que la conexión aún no está completamente cerrada.
  3. Si siempre termino la (última) actividad no solo con finish(), sino también con Runtime.getRuntime(). Exit (0) ;, funciona mucho mejor. Ve figura de nuevo ...

Si alguien puede explicar esto, con mucho gusto aprenderé. /por

(adición 3) Finalmente obtuvo la (2.2) la actualización de Froyo para mi deseo, y por lo que puedo ver, SPP ahora trabaja :) /por

2

que estaba desarrollando una aplicación que se conecta a un dispositivo BT. Tu código funciona bien en mi HTC Wildfire pero con un Samsung Galaxy I5700 no funciona. Ambos son OS 2.1 actualización, pero .....

La excepción fue 'InvocationTargetException'

Lo único que tuve que modificar es la falta de conexión().

private void disconnect() { 
     if(Conectado){ 
      try { 
       ***mBtSocket.close();*** 
       texto.setText(texto.getText()+"\nDesconectado"); 
       Conectado = false; 
      } catch (IOException e1) { 
       // TODO Auto-generated catch block 
       texto.setText(texto.getText()+"\n"+e1.getMessage()); 
      } 
      catch (Exception e2) { 
       // TODO Auto-generated catch block 
       texto.setText(texto.getText()+"\n"+e2.getMessage()); 
      }  
     } 
1

Hey, así que he estado usando la aplicación de chat de Bluetooth desde el sitio de desarrollo de Android y proporcionan un método en la clase stop() BluetoothChatService. Así que simplemente creé una instancia en mi clase principal y llamé a la función de detención desde mi botón de desconexión.

Así es como puedo llamar en mi clase principal

// objeto miembro a los servicios de chat

private BluetoothManager mChatService = null; 
case R.id.disconnect: 
     mChatService.stop(); 
break; 

El método stop() en BluetoothChatService

private AcceptThread mAcceptThread; 
private ConnectThread mConnectThread; 
public synchronized void stop() 
{ 
    if (mConnectThread != null) 
    { 
     mConnectThread.cancel(); mConnectThread = null; 
    } 
    if (mConnectedThread != null) 
    { 
     mConnectedThread.cancel(); mConnectedThread = null; 
    } 
    if (mAcceptThread != null) 
    { 
     mAcceptThread.cancel(); mAcceptThread = null; 
    } 
} 
0

tengo el mismo problema. Este es el problema con el Módulo Bluetooth CSR BC417, presente en muchos dispositivos como adaptador serie a bluetooth con perfil SPP. Con otro módulo Bluetooth, el dispositivo Android funciona bien, y el bluetooth libera la conexión después de que se cierra el socket, pero con dispositivos con este núcleo CSR no. Probado en SPP Bluetooth a adaptador serie basado en CSR BC417, y módulo Bluetooth de Actisys. Ambos con dispositivos Android 4.0. No sé por qué, pero es un problema de compatibilidad entre harwares, intente cambiar el adaptador de serie por otro con un núcleo diferente. Pruebo programáticamente para encontrar una solución, incluso deshabilitar un bluetooth, pero es imposible, el problema se origina en el módulo CSR.

+1

Nunca comience una respuesta con "Tengo el mismo problema". Tuve que leer con mucho cuidado para determinar que realmente hay información potencialmente útil aquí. –

12

Descubrí que si llamo a socket.close() demasiado pronto después de una comunicación reciente a través de OutputStream, el cierre falla y no puedo volver a conectar. Agregué un Thread.sleep (1000) justo antes de la llamada para cerrar() y esto parece resolverlo.

+0

solución de djilk funciona para mí!, Agregando el Thread.sleep (1000) antes de restablecer la conexión libera el bluetooth. Probado en 3 dispositivos SPP incluido CsR 417 Gracias. – user3523720

+0

¡También funciona para mí! ¡Gracias! – Stucky