2012-01-24 92 views
2

我对Android非常陌生。现在我正在尝试使用蓝牙API制作双人Pong游戏。我已经或多或少地尝试在Android网站上复制BluetoothChat教程,但是在切换到ConnectedThread后,套接字立即断开,但仍然出现错误。谁会知道为什么这是?Android BluetoothSocket连接后立即断开连接

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

}

+0

请告诉我您的sdk版本! – NovusMobile

回答

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