Android BluetoothSocket连接后立即断开连接

时间:2012-01-24 03:15:17

标签: android sockets bluetooth

我对Android很新。现在我正在尝试使用蓝牙API制作双人Pong游戏。我或多或少试图在Android网站上复制BluetoothChat教程,但是在切换到ConnectedThread后套接字立即断开连接时仍然出现错误。有人会知道为什么会这样吗?

我将三种类型的线程中的每一种都作为菜单屏幕上的私有类。 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) { }
}

}

1 个答案:

答案 0 :(得分:2)

尝试使用反射:

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设备上使用蓝牙连接时遇到了这个问题。