12

SDK 10(2.3.3)用にコンパイルしています:

android:minSdkVersion="10"
android:targetSdkVersion="16"

私は2台のSonyEricssonスマートフォンでテストしています。1つにはAndroid2.3.7が搭載されており、もう1つには4.0.1が搭載されています。

listenUsingInsecureRfcommWithServiceRecordBluetoothで新しいサーバーソケットを開き、接続をリッスンするために使用しています。

接続が正常に受け入れられると、すべてが正常に機能します。サーバーソケットをキャンセルすることもできますが、作成したばかりの接続ソケットを気にする必要はないようです。

しかし、回線が実行されるとすぐに接続を受け入れる前にサーバーソケットをキャンセルしたい場合はbluetoothServerSocket.close();、アクティビティ全体が閉じてプロセスが終了します。さらに、これは私が処理できる通常の例外ではありません。

実はlogcat自体もやめます!! そして、以下に表示されるエラーを取得するために、すぐに再度実行する必要があります。

Zygote  D  Process 25471 terminated by signal (11)
  295         InputDispatcher  W  channel '2c2e20a8 com.pligor.test/activities.MainActivity (server)' ~ Consumer closed input channel or an error occurred.  events=0x8
  295         InputDispatcher  E  channel '2c2e20a8 com.pligor.test/activities.MainActivity (server)' ~ Channel is unrecoverably broken and will be disposed!
  295                dalvikvm  D  GC_FOR_ALLOC freed 1299K, 21% free 13252K/16583K, paused 93ms
  295         InputDispatcher  W  Attempted to unregister already unregistered input channel '2c2e20a8 com.pligor.test/activities.MainActivity (server)'
  295        BluetoothService  D  Tracked app 25471 diedType:10
  295        BluetoothService  D  Removing service record 10009 for pid 25471
  132          SurfaceFlinger  D  Release buffer at 0x61c08
  295           WindowManager  I  WINDOW DIED Window{2c2e20a8 com.pligor.test/activities.MainActivity paused=false}
  295         ActivityManager  I  Process com.pligor.test (pid 25471) has died.
  295         ActivityManager  W  Force removing ActivityRecord{2c021800 com.pligor.test/activities.MainActivity}: app died, no saved state
  295           WindowManager  W  Failed looking up window
  295           WindowManager  W  java.lang.IllegalArgumentException: Requested window android.os.BinderProxy@2bf3e798 does not exist
  295           WindowManager  W    at com.android.server.wm.WindowManagerService.windowForClientLocked(WindowManagerService.java:7165)
  295           WindowManager  W    at com.android.server.wm.WindowManagerService.windowForClientLocked(WindowManagerService.java:7156)
  295           WindowManager  W    at com.android.server.wm.WindowState$DeathRecipient.binderDied(WindowState.java:1545)
  295           WindowManager  W    at android.os.BinderProxy.sendDeathNotice(Binder.java:417)
  295           WindowManager  W    at dalvik.system.NativeStart.run(Native Method)
  295           WindowManager  I  WIN DEATH: null
  295      BluetoothEventLoop  D  Property Changed: UUIDs : 11
  295    hAdapterStateMachine  D  BluetoothOn process message: 51
  295     InputManagerService  W  Got RemoteException sending setActive(false) notification to pid 25471 uid 10040

注:シグナル(11)で終了したプロセスは、セグメンテーション違反(http://en.wikipedia.org/wiki/SIGSEGV)を意味します。

編集

次のコード( )を使用してBluetoothサーバーソケットを作成します。Scala

private val bluetoothServerSocket: BluetoothServerSocket = try {
    bluetoothAdapter.listenUsingInsecureRfcommWithServiceRecord(MY_SERVICE_NAME_INSE‌​CURE, MY_UUID_INSECURE); 
} 
catch { 
    case e: IOException => throw new ServerSocketException; 
} 

このコードを使用してBluetoothソケットを閉じます。

try { 
    isCancelled = true; 
    bluetoothServerSocket.close(); 
} catch { 
    case e: IOException => throw new NotClosedException; 
}
4

3 に答える 3

6

私も同様の問題を経験しましたが、問題の根本的な原因は、ソケットを2回以上閉じることでした。この問題を修正するために、Bluetoothソケットを特別なクラスでラップして、closeメソッドが複数回呼び出されないようにしました。

Bluetoothソケットによって作成されたストリームを閉じると、ソケットでcloseを呼び出すことができることに注意してください。以下は問題を解決します。

public class CloseOnceBluetoothSocket 
{
private final BluetoothSocket mSocket;
private boolean mIsClosed;

public CloseOnceBluetoothSocket(BluetoothSocket socket)
{
    this.mSocket = socket;
}

public void connect() throws IOException
{
    mSocket.connect();
}

public InputStream getInputStream() throws IOException
{
    return new FilterInputStream(mSocket.getInputStream()) {
        @Override
        public void close() throws IOException
        {
            CloseOnceBluetoothSocket.this.close();
        }
    };
}

public OutputStream getOutputStream() throws IOException
{
    return new FilterOutputStream(mSocket.getOutputStream()) {
        @Override
        public void close() throws IOException
        {
            CloseOnceBluetoothSocket.this.close();
        }
    };
}

public void close() throws IOException
{
    synchronized (mSocket) {
        if (!mIsClosed) {
            mSocket.close();
            mIsClosed = true;
        }
    }
}
}
于 2013-02-28T19:28:08.863 に答える
2

ソケットを閉じると大きな損傷が発生する場合は、ユーザーが接続しているときにtrueに設定され、ユーザーが切断しているときにfalseに設定されるブールフラグを作成してみませんか。次に、ユーザーが以前に接続したときにのみcloseを呼び出します。

于 2013-02-23T22:18:34.470 に答える
0

この問題の回避策を見つけたと思います。「私が思う」は、これがまだ多くのデバイスでテストされていないためです。

以下のコードはScalaです

回避策として、タイムアウトのあるオーバーロードされたメソッドaccept(int)を利用します

したがって、以下に表示されている無限ループの状態の変数があります

private var toContinue = true;

whileループで受け入れることを繰り返すだけです

while (toContinue) {
  try {
    //this is a blocking call and will only return on a successful connection or an exception, or on timeout
    val socket = bluetoothServerSocket.accept(10000); //msec

    connectionAccepted(socket);
  } catch {
    case e: IOException => {
      Logger("accepting timed out");
    }
  }
}

だから今、私たちは呼び出す代わりに、bluetoothServerSocket.close()変数をfalseに設定しているだけです

def cancel() {
    toContinue = false;
}

whileループの終了時に何かを実行するためにコールバック関数が必要なため、実際のコードは少し複雑ですが、主な問題は上記のように解決されています

于 2013-03-09T00:13:32.697 に答える