android - 接続後すぐにAndroid BluetoothSocketが切断される

android sockets bluetooth

私はAndroidにかなり慣れていません。現在、私はBluetooth APIを使用して2人用のPongゲームを作成しようとしています。 AndroidウェブサイトでBluetoothChatチュートリアルをコピーしようとしたのですが、ConnectedThreadに切り替えた直後にソケットがすぐに切断されるというエラーが発生します。これがなぜなのか誰か誰か知っていますか?

メニューの画面に、3種類のスレッドをそれぞれプライベートクラスとして持っています。 ConnectThreadは読み取りと書き込みに分割され、ゲームの画面内に配置されます。

public abstract class FindScreen extends EngineView {

private GUIFactory guiFact;

private TextButton backButton;
private ScrollingList buttonList;

public ConnectThread connectThread;
private BluetoothAdapter adapter;

public FindScreen(Context c, AndroidView aView) {
    super(c, aView, 1);
    adapter = BluetoothAdapter.getDefaultAdapter();

    guiFact = new GUIFactory(new Vector2d(EngineConstants.CENTER_X,
            EngineConstants.CENTER_Y), 8, 8, EngineConstants.VIRTUAL_W,
            EngineConstants.VIRTUAL_H, EngineConstants.VIRTUAL_W / 32);

    GUITask backTask = new GUITask() {
        public void execute() {
            goBack();
        }
    };
    backButton = guiFact.newGradientTextButton(1, 6, 7, 7, backTask, "Back"); 
    this.add(backButton, 0);

    buttonList = guiFact.newScrollingList(1,1,7,6);
    this.add(buttonList, 0);
}

@Override
public boolean onTouchEvent(MotionEvent e) {
    backButton.executeIfContained(e.getX(), e.getY());
    buttonList.executeIfContained(e.getX(), e.getY());
    return true;
}

public void onIn() {
    // Register for broadcasts when a device is discovered
    IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
    context.registerReceiver(receiver, filter);

    // Register for broadcasts when discovery has finished
    filter = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
    context.registerReceiver(receiver, filter);
    buttonList.clearButtons();
    if(!adapter.startDiscovery()) { // if discovery doesn't start successfully, leave the screen
        goBack();
    }
}

public void onOut() {
    if (adapter.isDiscovering()) {
        adapter.cancelDiscovery();
    }
    context.unregisterReceiver(receiver);
    if (connectThread != null) {
        connectThread.cancel();
    }
}

/**
 * Return to the previous screen, the menu screen
 */
public abstract void goBack();

/**
 * Do something after we've connected
 * @param socket
 */

public abstract void connected(BluetoothSocket socket);

/**
 * Broadcast receiver;
 * Listens for discovered devices
 * When discovery is finished, changes the list of discovered devices
 * When discoverability is changed, changes text
 */

private final BroadcastReceiver receiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();

        if (BluetoothDevice.ACTION_FOUND.equals(action)) {
            BluetoothDevice device = intent
                    .getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);

            // if (device.getBondState() != BluetoothDevice.BOND_BONDED) {
            buttonList.addButton(device.getName(), new ConnectTask(device.getAddress()));
            // }
            // doDiscovery();
        }
    }
};

private class ConnectTask extends GUITask {

    private String address;

    public ConnectTask(String addr) {
        address = addr;
    }

    @Override
    public void execute() {
        BluetoothDevice device = adapter.getRemoteDevice(address);
        if (connectThread != null) {
            connectThread.cancel();
        }
        connectThread = new ConnectThread(device);
        connectThread.start();
    }

}

private class ConnectThread extends Thread {
    private final BluetoothSocket socket;
    private final BluetoothDevice device;

    public ConnectThread(BluetoothDevice dev) {
        // Use a temporary object that is later assigned to mmSocket,
        // because mmSocket is final
        BluetoothSocket tmp = null;
        device = dev;

        // Get a BluetoothSocket to connect with the given BluetoothDevice
        try {
            // MY_UUID is the app's UUID string, also used by the server code
            tmp = device.createRfcommSocketToServiceRecord(EngineConstants.MY_UUID);
        } catch (IOException e) { }
        socket = tmp;
    }

    public void run() {
        // Cancel discovery because it will slow down the connection

        if (adapter.isDiscovering()) {
            adapter.cancelDiscovery();
        }

        try {
            // Connect the device through the socket. This will block
            // until it succeeds or throws an exception
            socket.connect();
        } catch (IOException connectException) {
            // Unable to connect; close the socket and get out
            try {
                socket.close();
            } catch (IOException closeException) { }
            return;
        }

        // Do work to manage the connection (in a separate thread)
        connected(socket);
    }

    /** Will cancel an in-progress connection, and close the socket */
    public void cancel() {
        try {
            socket.close();
        } catch (IOException e) { }
    }
}




public abstract class HostScreen extends EngineView {

private GUIFactory guiFact;
private TextButton backButton;
private TextLabel waitText;

private BluetoothAdapter adapter;

public AcceptThread acceptThread;

private static final int DISCOVERY_LENGTH = 300;

public HostScreen(Context c, AndroidView aView) {
    super(c, aView, 1);
    adapter = BluetoothAdapter.getDefaultAdapter();

    guiFact = new GUIFactory(new Vector2d(EngineConstants.CENTER_X,
            EngineConstants.CENTER_Y), 8, 8, EngineConstants.VIRTUAL_W,
            EngineConstants.VIRTUAL_H, EngineConstants.VIRTUAL_W / 32);

    GUITask backTask = new GUITask() {
        public void execute() {
            goBack();
        }
    };
    backButton = guiFact.newGradientTextButton(1, 6, 7, 7, backTask, "Back"); 
    this.add(backButton, 0);

    waitText = guiFact.newLabel(2, 3, 6, 4, Color.WHITE, "...");
    this.add(waitText, 0);
}

public void onIn() {
    if (adapter.getScanMode() != BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
        Intent discoverableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
        discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, DISCOVERY_LENGTH);
        ((Activity) context).startActivityForResult(discoverableIntent, EngineConstants.REQUEST_DISCOVERABLE);
    }
    if (!adapter.isEnabled()) {
        Intent enableIntent = new Intent(
                BluetoothAdapter.ACTION_REQUEST_ENABLE);
        context.startActivity(enableIntent);
    }       
}

public void onOut() {
    if (acceptThread != null) {
        acceptThread.cancel();
    }
}

public void discoverableAccepted() {
    if (acceptThread != null) {
        acceptThread.cancel();
    }
    acceptThread = new AcceptThread();
    acceptThread.start();
}

public void discoverableDeclined() {
    goBack();
}

/**
 * Do something after we've connected
 * @param socket
 */

public abstract void connected(BluetoothSocket socket);

@Override
public boolean onTouchEvent(MotionEvent e) {
    backButton.executeIfContained(e.getX(), e.getY());
    return true;
}

/**
 * Return to the previous screen, the menu screen
 */
public abstract void goBack();

private class AcceptThread extends Thread {
    private final BluetoothServerSocket serverSocket;

    public AcceptThread() {
        // Use a temporary object that is later assigned to mmServerSocket,
        // because mmServerSocket is final
        BluetoothServerSocket tmp = null;
        try {
            // MY_UUID is the app's UUID string, also used by the client code
            tmp = adapter.listenUsingRfcommWithServiceRecord(EngineConstants.NAME, EngineConstants.MY_UUID);
        } catch (IOException e) { }
        serverSocket = tmp;
    }

    public void run() {
        BluetoothSocket socket = null;
        // Keep listening until exception occurs or a socket is returned
        while (true) {
            try {
                socket = serverSocket.accept();
            } catch (IOException e) {
                break;
            }
            // If a connection was accepted
            if (socket != null) {
                // Do work to manage the connection (in a separate thread)
                connected(socket);
                try {
                    serverSocket.close();
                } catch (IOException e) {
                    android.util.Log.d("Accept thread", "Could not close serverSocket");
                }
                break;
            }
        }
    }

    /** Will cancel the listening socket, and cause the thread to finish */
    public void cancel() {
        try {
            serverSocket.close();
        } catch (IOException e) { }
    }
}


}



public class GameScreen extends EngineView {

public ConnectedThread connectedThread;
public ConnectedWriteThread writeThread;
private PacketHandler handler;

private final static int N_LAYERS = 4;
// layer 0 = walls
// layer 1 = puck
// layer 2 = paddles
// layer 3 = GUI

public Paddle enemyPaddle, playerPaddle;
public Puck puck;

private GUIFactory guiFact;
private TextLabel playerLabel, enemyLabel;
public int playerScore = 0, enemyScore = 0;

private boolean isHeld;
private float startX, startTouchX, moveToX;
private final static float MIN_X = Paddle.RADIUS, MAX_X = EngineConstants.VIRTUAL_W - MIN_X;

public float myPaddlePrevPosX;
public boolean enemyScoreChanged = false;

private final static long PACKET_RATE = 200;
private long packetTime = 0;

public GameScreen(Context c, final AndroidView aView) {
    super(c, aView, N_LAYERS);

    enemyPaddle = new Paddle(new Vector2d(EngineConstants.CENTER_X, EngineConstants.VIRTUAL_H/8f), 255, 255, 100, 100);
    playerPaddle = new Paddle(new Vector2d(EngineConstants.CENTER_X, EngineConstants.VIRTUAL_H*7f/8f), 255, 100, 255, 100);

    puck = new Puck();

    this.add(enemyPaddle, 2);
    this.add(playerPaddle, 2);
    this.add(puck, 1);

    guiFact = new GUIFactory(new Vector2d(EngineConstants.CENTER_X, EngineConstants.CENTER_Y), 8, 10, EngineConstants.VIRTUAL_W, EngineConstants.VIRTUAL_H, 0);
    playerLabel = guiFact.newLabel(2, 4, 3, 5, Color.rgb(100, 150, 100), "0");
    enemyLabel = guiFact.newLabel(7, 3, 8, 4, Color.rgb(150, 100, 100), "0");

    this.add(playerLabel, 3);
    this.add(enemyLabel, 3);

    this.constraints.add(new BoxConstraint(puck, false, false, 0 + Puck.RADIUS));
    this.constraints.add(new BoxConstraint(puck, false, true, EngineConstants.VIRTUAL_W - Puck.RADIUS));

    myPaddlePrevPosX = playerPaddle.pos.x;
}

public void onOut() {
    if (connectedThread != null) {
        connectedThread.cancel();
    }
    if (writeThread != null) {
        writeThread.cancel();
    }
}

public void update(long interval) {
    super.update(interval);
    EngineFunctions.collide(playerPaddle, puck);
    EngineFunctions.collide(enemyPaddle, puck);
    if (puck.pos.y < 0) {
        score(true);
    } else if (puck.pos.y > EngineConstants.VIRTUAL_H) {
        score(false);
    }

    packetTime += interval;
    if (packetTime > PACKET_RATE) {
        // android.util.Log.d("fillQueue", "called");
        packetTime = 0;
        writeThread.fillQueue();
    }
}

private void score(boolean isPlayer) {
    if (isPlayer) {
        playerScore++;
        playerLabel.setText(String.valueOf(playerScore));
    } else {
        enemyScore++;
        enemyLabel.setText(String.valueOf(enemyScore));
        enemyScoreChanged = true;
    }
    puck.pos.x = EngineConstants.CENTER_X;
    puck.pos.y = EngineConstants.CENTER_Y;
    puck.prevPos.x = EngineConstants.CENTER_X;
    puck.prevPos.y = EngineConstants.CENTER_Y;
}

@Override
public boolean onTouchEvent(MotionEvent e) {
    switch(e.getAction()) {
    case MotionEvent.ACTION_DOWN:
        if (playerPaddle.touching(e.getX(), e.getY())) {
            isHeld = true;
            startX = playerPaddle.pos.x;
            startTouchX = e.getX();
        }
        break;
    case MotionEvent.ACTION_MOVE:
        if (isHeld) {
            myPaddlePrevPosX = playerPaddle.pos.x;
            moveToX = startX + (e.getX() - startTouchX);
            if (moveToX < MIN_X) {
                moveToX = MIN_X;
            } else if (moveToX > MAX_X) {
                moveToX = MAX_X;
            }
            playerPaddle.pos.x = moveToX;
            playerPaddle.prevPos.x = moveToX;
        }
        break;
    case MotionEvent.ACTION_UP:
        isHeld = false;
        break;
    }
    return true;
}

public void startNewConnectedThread(BluetoothSocket soc, boolean isServer) {
    if (connectedThread != null) {
        connectedThread.cancel();
    }
    connectedThread = new ConnectedThread(soc, handler);
    connectedThread.start();

    if (writeThread != null) {
        writeThread.cancel();
    }
    writeThread = new ConnectedWriteThread(soc, handler, isServer);
    writeThread.start();
}

public void setHandler(PacketHandler h) {
    handler = h;
}




public class ConnectedThread extends Thread {
private final BluetoothSocket socket;
private final InputStream inStream;

private final BufferedReader in;

private PacketHandler handler;

public ConnectedThread(BluetoothSocket soc, PacketHandler pHandler) {
    socket = soc;
    handler = pHandler;
    InputStream tmpIn = null;

    // Get the input and output streams, using temp objects because
    // member streams are final
    try {
        tmpIn = socket.getInputStream();
    } catch (IOException e) {

    }

    inStream = tmpIn;

    in = new BufferedReader(new InputStreamReader(inStream));
}

public void run() {
    /*
    // Keep listening to the InputStream until an exception occurs
    android.util.Log.d("connectedThread", "started");
    String str;
    try {
        inStream.read();
        inStream.read();
    } catch (IOException e1) {
        // TODO Auto-generated catch block
        e1.printStackTrace();
    }
    android.util.Log.d("connectedThread", "normal read is fine");

    while (true) {

        try {
            // Read from the InputStream
            str = in.readLine();
            byte type = Byte.valueOf(str);
            android.util.Log.d("connectedThread", "read");
            handler.handlePacket(in, type);
        } catch (IOException e) {
            break;
        }
    }*/

    for (int i = 0; i < 20; i++) {
        try {
            String str = in.readLine();
            android.util.Log.d("read", str + " ");
        } catch (IOException e) {
            // TODO Auto-generated catch block
            android.util.Log.d("io exception", e.getMessage() + " " + e.getLocalizedMessage() + " " + e.getCause());
        }

    }
    while (true) {

    }

}

/* Call this from the main Activity to shutdown the connection */
public void cancel() {
    try {
        socket.close();
    } catch (IOException e) { }
}


}



public class ConnectedWriteThread extends Thread {
public ConcurrentLinkedQueue<String> que;

private final BluetoothSocket socket;
private final OutputStream outStream;

private final BufferedWriter out;

private PacketHandler handler;

private boolean isServ;

public ConnectedWriteThread(BluetoothSocket soc, PacketHandler pHandler, boolean isServer) {
    socket = soc;
    handler = pHandler;
    isServ = isServer;
    OutputStream tmpOut = null;
    que = new ConcurrentLinkedQueue<String>();

    // Get the input and output streams, using temp objects because
    // member streams are final
    try {
        tmpOut = socket.getOutputStream();
    } catch (IOException e) { }

    outStream = tmpOut;

    out = new BufferedWriter(new OutputStreamWriter(outStream));
}

public void run() {
    // Keep listening to the InputStream until an exception occurs
    android.util.Log.d("connectedThread", "started");
    /*
    try {
        if (isServ) {
            out.write(String.valueOf(EngineConstants.PACKET_SYNC) + '\n');
            out.write(String.valueOf(0) + '\n');
        }
    } catch (IOException e1) {
        android.util.Log.d("connectedThread", "io exception " + e1.getMessage() + " " + e1.getLocalizedMessage() + " " + e1.getCause());
    }
    //android.util.Log.d("connectedThread", "sent initial packet");
    while (true) {
        if (!que.isEmpty()) {
            try {
                out.write(que.poll());
                out.flush();
                // android.util.Log.d("connectedThread", "sent packet");
            } catch (IOException e) {
                android.util.Log.d("write thread", "io exception " + e.getMessage());
            }
        }
    }*/
    try {
        outStream.write(3);
        out.write("343567\n");
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    while (true) {

    }
}

public void fillQueue() {
    // android.util.Log.d("fillQueue", "in method");
    handler.queuePacket(que);
}

/* Call this from the main Activity to send data to the remote device */
public void write(String str) {
    try {
        out.write(str);
    } catch (IOException e) { }
}

/* Call this from the main Activity to shutdown the connection */
public void cancel() {
    try {
        socket.close();
    } catch (IOException e) { }
}


}
答え
リフレクションを使用してみてください:

try {
    BluetoothDevice mDevice = mBluetoothAdapter.getRemoteDevice("MAC of remote device");
    Method m = mDevice.getClass().getMethod("createRfcommSocket",
                new Class[] { int.class });
    mSocket = (BluetoothSocket) m.invoke(mDevice, Integer.valueOf(1));
    mSocket.connect();
} catch (NoSuchMethodException e) {
} catch (SecurityException e) {
} catch (IllegalArgumentException e) {
} catch (IllegalAccessException e) {
} catch (InvocationTargetException e) {
} catch (Exception e) {}


そしてしばらくしてあなたのスレッドで

mInStream = mSocket.getInputStream();
mOutStream = mSocket.getOutputStream();


mInStreamはInputStream()で、mOutStreamはOutputStream()です。

HTCデバイスでBluetooth接続を使用すると、この問題が発生しました。
関連記事

android - WiFiフレーム(レイヤー2 PDU)を変更して新しいフィールドを含めることは可能ですか?

android - Android VideoView OnCompletionListenerが機能しない

android - ICSで顔認証が有効になっているかどうかを検出するにはどうすればよいですか?

android - Maven、ActionBarSherlock v4、Roboguice v2-ビルドするにはどうすればよいですか?

java - Bluetooth通信用の軽量対称鍵アルゴリズム?

php - WindowsのApacheでexecを実行する

android - Android向けのsendDataMessage()の動作例

android - AndroidでTabLayoutを使用しているときにすべてのアクティビティを更新するにはどうすればよいですか?

android - 多数のテキスト行とスタイルを持つEditTextで2Dスクロールを有効にします

android - レイアウトが明示的に宣言されていない場合、アクティビティのデフォルトのレイアウトは何ですか?