web-dev-qa-db-ja.com

AndroidでBluetoothソケットを切断します

Android Phoneから、クライアントとしてBluetooth医療センサーに接続する必要があります。公式のBluetooth APIを使用しており、接続中に問題はありません( SPPプロファイル)、ただし、ソケットを終了しても、センサーは引き続き電話機に接続されています(ただし、接続は閉じています)。

Bluetoothを切断する方法はありますか?それを行うACTION_ACL_CONNECTEDと呼ばれる意図があると思います。誰もこれを使用する方法を説明できますか?

前もって感謝します。

編集済み:コードは次のとおりです。追加情報が必要な場合は、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();
                    }
                }
            }
        }
}
40
user365610

最初に入出力ストリームを必ず閉じてから、ソケットを閉じてください。

ストリームを閉じることにより、切断プロセスを開始します。ソケットを閉じると、接続が完全に切断されます。

ストリームの前にソケットを閉じると、物理層接続の(適切な)クローズなど、特定のシャットダウン手順をバイパスしている可能性があります。

接続を中断するときに使用する方法を次に示します。

/**
 * 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;
        }

}

編集: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;
}
63
Brad Hein

OutputStreamを介した最近の通信の直後にsocket.close()を呼び出すと、クローズに失敗し、再接続できないことがわかりました。 close()を呼び出す直前にThread.sleep(1000)を追加しましたが、これで解決するようです。

16
djilk

こんにちは、

私はまったく同じ問題を見ました(HTC Desire)。本でソケットを閉じたにもかかわらず(Bradが示唆しているように)、次のconnect()は永久にブロックします-別のスレッドによるclose()で終了するまで。

接続する前に常にBluetoothAdapter.disable()/。enable()を呼び出すことで問題を回避しました。ひどい、非友好的なハック、私は知っている...

一部のアプリの実装者はcreateRfcommSocketToServiceRecord()で問題なく動作しているように見えるため、現在のBTの問題のいくつかはメーカー固有のものであると思われます。

HTC DesireのBTスタックはNexus Oneとは異なるという兆候を見ました(参照はありません)。

BRあたり

(追加)これは、問題を再現するための非常に簡単なアクティビティです(「キュア」を無効/有効にせずに):

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");       
    }
}

私が間違ってやっている場合、誰かが見つけられるなら、コメントしてください:)

(addition 2)私は今すぐ動作するようになったと思う:

  1. (SDPを介して)RFCOMMを接続する公式の方法は、実際に機能しているようです(HTC Desire、2.1アップデート1)、[〜#〜] but [〜#〜]削除して再ペアリングする必要がありましたBTデバイス。図を行く..
  2. 「速すぎる」再接続(アプリを終了してすぐに再起動する)を行うと、再接続が失敗する場合があります(サービス検出エラー)。接続がまだ完全にダウンしていないと思います。
  3. Finish()だけでなくRuntime.getRuntime()。exit(0);でも(最後の)アクティビティを常に終了する場合は、はるかにうまく機能します。再び図に行く...

誰かがこれを説明できるなら、私は喜んで学びます。 /あたり

(追加3)ついに私の欲望のFroyo(2.2)アップデートを入手し、私が見る限り、SPPが動作するようになりました:)/Per

11
Per Laursen

BTデバイスに接続するアプリを開発していました。 HTC Wildfireでコードは正常に機能しますが、Samsung Galaxy I5700では機能しません。どちらのOSも2.1アップデートですが、.....

例外は「InvocationTargetException」でした

変更しなければならなかったのは、disconnect()だけです。

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());
            }    
         }
2
user343464

だから私はAndroid開発サイトからBluetoothチャットアプリケーションを使用していて、BluetoothChatServiceクラスでstop()メソッドを提供しているので、単純に自分のインスタンスを作成しましたメインクラスと私の切断ボタンから停止機能を呼び出しました。

これがメインクラスでの呼び方です

//チャットサービスのメンバーオブジェクト

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

BluetoothChatServiceのstop()メソッド

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;
    }
}
1
Rafael Mancilla

同じ問題があります。これは、BluetoothモジュールCSR BC417の問題で、多くのデバイスにSPPプロファイルを備えたBluetoothアダプターへのシリアルとして存在します。別のBluetoothモジュールではAndroidデバイスは正常に動作し、Bluetoothはソケットが閉じられた後に接続を解放しますが、このCSRコアを持つデバイスではそうではありません。CSRBC417に基づくSPP Bluetooth to Serial Adapter 、およびActisysのBluetoothモジュール。両方ともAndroid 4.0デバイスです。理由はわかりませんが、ハーウェア間の互換性の問題です。別のコアを持つシリアルアダプタを別のコアに変更してみてください。ブルートゥースを無効にすることもできますが、不可能な解決策を見つけるために、トラブルはCSRモジュールに起因します。

0
Cacho Paraguay