我对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) { }
}
}
答案 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设备上使用蓝牙连接时遇到了这个问题。