我正在尝试通过我的Android应用程序中的Bluetooth
传递对象。因此,我必须序列化它并将其从我的(GameViewHandler)
活动传递到我的BluetoothConnectionService class.
问题是对象(Ball)无法序列化并抛出NotSerializableExeption.
我尝试通过在此问题中实施serialize()
方法来完成序列化:https://stackoverflow.com/a/14165417/4408098
以下是调用write()
中的BluetoothConnectionService
方法的活动:
public class GameActivityHandler extends Activity {
private static final String TAG = "GameActivityHandler";
private BluetoothConnectionService mConnService;
private Ball myBall;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
View decorView = getWindow().getDecorView();
// Hide the status bar.
int uiOptions = View.SYSTEM_UI_FLAG_FULLSCREEN;
decorView.setSystemUiVisibility(uiOptions);
// Remember that you should never show the action bar if the
// status bar is hidden, so hide that too if necessary.
ActionBar actionBar = getActionBar();
actionBar.hide();
setContentView(new GameView(this));
Bundle extra = getIntent().getExtras();
Boolean isHost = extra.getBoolean("host");
if(isHost){
mConnService = BluetoothHostActivity.mBtService;
} else{
mConnService = JoinGameActivity.mConnService;
}
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
final AlertDialog ad = new AlertDialog.Builder(this).create();
ad.setMessage("Do you really want to disconnect?");
ad.setCancelable(false);
ad.setButton(AlertDialog.BUTTON_NEGATIVE, "No", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
ad.dismiss();
}
});
ad.setButton(AlertDialog.BUTTON_POSITIVE, "Yes", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
mConnService.cancelConnection();
Toast.makeText(GameActivityHandler.this, "Disconnected!", Toast.LENGTH_SHORT).show();
Intent intent = new Intent(GameActivityHandler.this, MainActivity.class);
startActivity(intent);
GameActivityHandler.this.finish();
}
});
ad.show();
return super.onKeyDown(keyCode, event);
}
/**
* The Handler that gets information back from the BluetoothChatService
*/
private final Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case 1:
// just receive a Toast
Toast.makeText(GameActivityHandler.this, msg.getData().getString("toast"),Toast.LENGTH_SHORT).show();
break;
case 2: // 2 stands for the MESSAGE_READ Integer
Log.d(TAG, "Handler just received message from BluetoothConnectionService");
byte[] readBuf = (byte[]) msg.obj;
Ball readMessage = null;
try {
readMessage = deserialize(readBuf); // deserialize the received byte[] to convert it back to a Ball object
} catch (ClassNotFoundException | IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Log.d(TAG, "Received Ball: xCoordinate: " + readMessage.getX() + " yCoordinate: " + readMessage.getY());
break;
case 3:
}
}
};
public static Ball deserialize(byte[] bytes) throws IOException, ClassNotFoundException {
ByteArrayInputStream b = new ByteArrayInputStream(bytes);
ObjectInputStream o = new ObjectInputStream(b);
return (Ball) o.readObject();
}
public void invokeWriteDataToBtService(Ball send) throws IOException {
// send a Ball object to the remote device through BluetoothConnectionService
// but serialize it first because OutPutStream only accepts byte Arrays to be sent over Bluetooth
mConnService.write(send.serialize());
}
}
基本上,invokeWriteDataToBtService()
方法很有意思。
我的BluetoothConnectionService:
public class BluetoothConnectionService {
private static final String TAG = "BluetoothConnectionService";
private static final String NAME = "ballGame";
private static final UUID MY_UUID =
UUID.fromString("9bf02da0-ff78-4a9d-a734-ef3e3324a4ec");
// Member fields
private final BluetoothAdapter mBluetoothAdapter;
private final Handler mHandler;
private ConnectThread mConnectThread;
private ConnectedThread mConnectedThread;
public BluetoothConnectionService(Context context, Handler handler) {
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
mHandler = handler;
}
public synchronized void accept(){
Log.d(TAG, "accept device");
// Start the thread to connect with the given device
AcceptThread mAcceptThread = new AcceptThread();
mAcceptThread.start();
}
public synchronized void connect(BluetoothDevice device){
Log.d(TAG, "connect to: " + device);
// Start the thread to connect with the given device
mConnectThread = new ConnectThread(device);
mConnectThread.start();
}
/**
* Start the ConnectedThread to begin managing a Bluetooth connection
*
* @param socket The BluetoothSocket on which the connection was made
* @param device The BluetoothDevice that has been connected
*/
public synchronized void connected(BluetoothDevice device, BluetoothSocket socket ) {
Log.d(TAG, "connected()");
// Cancel the thread that completed the connection
if (mConnectThread != null) {
mConnectThread.cancel();
mConnectThread = null;
}
// Cancel any thread currently running a connection
if (mConnectedThread != null) {
mConnectedThread.cancel();
mConnectedThread = null;
}
// Start the thread to manage the connection and perform transmissions
mConnectedThread = new ConnectedThread(socket);
mConnectedThread.start();
// Send the name of the connected device back to the UI Activity
Message msg = mHandler.obtainMessage(1);
Bundle bundle = new Bundle();
bundle.putString("toast", "connected with: " + device.getName());
msg.setData(bundle);
mHandler.sendMessage(msg);
}
private class AcceptThread extends Thread {
private final BluetoothServerSocket mmServerSocket;
public AcceptThread() {
// Use a temporary object that is later assigned to mmServerSocket,
// because mmServerSocket is final
BluetoothServerSocket tmp = null;
// mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
try {
// MY_UUID is the app's UUID string, also used by the client code
tmp = mBluetoothAdapter.listenUsingRfcommWithServiceRecord(NAME, MY_UUID);
} catch (IOException e) { }
mmServerSocket = tmp;
}
public void run() {
Log.d(TAG, "BEGIN mAcceptThread" + this);
BluetoothSocket socket = null;
// Keep listening until exception occurs or a socket is returned
while (true) {
try {
socket = mmServerSocket.accept();
} catch (IOException e) {
Log.e(TAG, "accept() failed", e);
break;
}
// If a connection was accepted
if (socket != null) {
// Do work to manage the connection (in a separate thread)
synchronized (BluetoothConnectionService.this) {
connected(socket.getRemoteDevice(), socket);
}
try {
mmServerSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
break;
}
}
Log.i(TAG, "END mAcceptThread");
}
}
private class ConnectThread extends Thread {
private final BluetoothSocket mmSocket;
private final BluetoothDevice mmDevice;
public ConnectThread(BluetoothDevice device) {
// Use a temporary object that is later assigned to mmSocket,
// because mmSocket is final
BluetoothSocket tmp = null;
mmDevice = device;
// 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(MY_UUID);
} catch (IOException e) { }
mmSocket = tmp;
}
public void run() {
// Cancel discovery because it will slow down the connection
mBluetoothAdapter.cancelDiscovery();
try {
// Connect the device through the socket. This will block
// until it succeeds or throws an exception
mmSocket.connect();
} catch (IOException connectException) {
// Unable to connect; close the socket and get out
try {
mmSocket.close();
} catch (IOException closeException) { }
connectionFailed();
return;
}
// Reset the ConnectThread because we're done
synchronized (BluetoothConnectionService.this) {
mConnectThread = null;
}
// Do work to manage the connection (in a separate thread)
connected(mmDevice, mmSocket);
}
/** Will cancel an in-progress connection, and close the socket */
public void cancel() {
try {
mmSocket.close();
} catch (IOException e) { }
}
}
public void cancelConnection(){
ConnectedThread r;
synchronized (this) {
r = mConnectedThread;
}
r.cancel();
}
/**
* Indicate that the connection attempt failed and notify the UI Activity.
*/
private void connectionFailed() {
// Send a failure message back to the Activity
Message msg = mHandler.obtainMessage(1);
Bundle bundle = new Bundle();
bundle.putString("toast", "Unable to connect device");
msg.setData(bundle);
mHandler.sendMessage(msg);
}
/**
* Indicate that the connection was lost and notify the UI Activity.
*/
private void connectionLost() {
// Send a failure message back to the Activity
Message msg = mHandler.obtainMessage(1);
Bundle bundle = new Bundle();
bundle.putString("toast", "Device connection was lost");
msg.setData(bundle);
mHandler.sendMessage(msg);
// Start the service over to restart listening mode
// BluetoothConnectionService.this.start();
}
/**
* Write to the ConnectedThread in an unsynchronized manner
*
* @param out The bytes to write
* @see ConnectedThread#write(byte[])
*/
// this method gets called from the GameActivityHandler Activity
public void write(byte[] out) {
Log.d(TAG, "write() in BluetoothConnectionService executed!");
// Create temporary object
ConnectedThread r;
// Synchronize a copy of the ConnectedThread
synchronized (this) {
r = mConnectedThread;
}
// Perform the write unsynchronized in ConnectedThread
r.write(out);
}
/**
* This thread runs during a connection with a remote device.
* It handles all incoming and outgoing transmissions.
*/
private class ConnectedThread extends Thread {
private final BluetoothSocket mmSocket;
private final InputStream mmInStream;
private final OutputStream mmOutStream;
public ConnectedThread(BluetoothSocket socket) {
Log.d(TAG, "create ConnectedThread");
mmSocket = socket;
InputStream tmpIn = null;
OutputStream tmpOut = null;
// Get the BluetoothSocket input and output streams
try {
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
} catch (IOException e) {
Log.e(TAG, "temp sockets not created", e);
}
mmInStream = tmpIn;
mmOutStream = tmpOut;
}
public void run() {
Log.i(TAG, "BEGIN mConnectedThread");
byte[] buffer = new byte[1024];
int bytes;
// Keep listening to the InputStream while connected
while (true) {
try {
Log.d(TAG, "Read InputStream...");
// Read from the InputStream
bytes = mmInStream.read(buffer);
// Send the obtained bytes to the UI Activity
mHandler.obtainMessage(2, bytes, -1, buffer)
.sendToTarget();
Log.d(TAG, "Just sent message to Handler");
} catch (IOException e) {
Log.e(TAG, "disconnected", e);
connectionLost();
// Start the service over to restart listening mode
// BluetoothConnectionService.this.start();
break;
}
}
}
/**
* Write to the connected OutStream.
*
* @param buffer The bytes to write
*/
// the actual write method
public void write(byte[] buffer) {
Log.d(TAG, "write() in ConnectedThread executed!");
try {
mmOutStream.write(buffer);
// Share the sent message back to the UI Activity
// mHandler.obtainMessage(3, -1, -1, buffer)
// .sendToTarget();
} catch (IOException e) {
Log.e(TAG, "Exception during write", e);
}
}
public void cancel() {
if (mmInStream != null) {
try {mmInStream.close();} catch (Exception e) {}
}
if (mmOutStream != null) {
try {
mmOutStream.close();
} catch (Exception e) {}
}
if (mmSocket != null) {
try {
mmSocket.close();
} catch (Exception e) {}
}
try {
mmSocket.close();
} catch (IOException e) {
Log.e(TAG, "close() of connect socket failed", e);
}
}
}
}
应该序列化的Ball
类。它包含一些float
,Integer
,boolean
和Bitmap
:
public class Ball {
private int x, y;
private Bitmap bitmap;
private float currVelocityX = 0, currVelocityY = 0, lastVelocityY = 0;
private boolean touched = false;
public Ball(Resources resources, int x_pos, int y_pos) {
x = x_pos;
y = y_pos;
bitmap = BitmapFactory.decodeResource(resources, R.drawable.ball1);
}
public void drawBall(Canvas canvas){
canvas.drawBitmap(bitmap, x, y, null);
}
// some methods
public byte[] serialize() throws IOException {
ByteArrayOutputStream b = new ByteArrayOutputStream();
ObjectOutputStream o = new ObjectOutputStream(b);
o.writeObject(this);
Log.d("TAG", "Ball gets serialized()");
return b.toByteArray();
}
}
日志说的是什么:
12-31 11:44:35.792: W/System.err(7956): java.io.NotSerializableException: com.mhpproductions.ballgame.Ball
12-31 11:44:35.792: W/System.err(7956): at java.io.ObjectOutputStream.writeNewObject(ObjectOutputStream.java:1364)
12-31 11:44:35.792: W/System.err(7956): at java.io.ObjectOutputStream.writeObjectInternal(ObjectOutputStream.java:1671)
12-31 11:44:35.792: W/System.err(7956): at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:1517)
12-31 11:44:35.792: W/System.err(7956): at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:1481)
12-31 11:44:35.792: W/System.err(7956): at com.mhpproductions.ballgame.Ball.serialize(Ball.java:104)
12-31 11:44:35.792: W/System.err(7956): at com.mhpproductions.ballgame.GameActivityHandler.invokeWriteDataToBtService(GameActivityHandler.java:125)
12-31 11:44:35.792: W/System.err(7956): at com.mhpproductions.ballgame.GameView.onTouchEvent(GameView.java:131)
12-31 11:44:35.792: W/System.err(7956): at android.view.View.dispatchTouchEvent(View.java:7713)
12-31 11:44:35.792: W/System.err(7956): at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2216)
12-31 11:44:35.792: W/System.err(7956): at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1959)
12-31 11:44:35.792: W/System.err(7956): at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2216)
12-31 11:44:35.792: W/System.err(7956): at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1959)
12-31 11:44:35.792: W/System.err(7956): at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2216)
12-31 11:44:35.792: W/System.err(7956): at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1959)
12-31 11:44:35.792: W/System.err(7956): at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:2329)
12-31 11:44:35.792: W/System.err(7956): at com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1568)
12-31 11:44:35.792: W/System.err(7956): at android.app.Activity.dispatchTouchEvent(Activity.java:2458)
12-31 11:44:35.792: W/System.err(7956): at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:2277)
12-31 11:44:35.792: W/System.err(7956): at android.view.View.dispatchPointerEvent(View.java:7893)
12-31 11:44:35.792: W/System.err(7956): at android.view.ViewRootImpl$ViewPostImeInputStage.processPointerEvent(ViewRootImpl.java:3950)
12-31 11:44:35.792: W/System.err(7956): at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:3829)
12-31 11:44:35.792: W/System.err(7956): at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3395)
12-31 11:44:35.792: W/System.err(7956): at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3445)
12-31 11:44:35.792: W/System.err(7956): at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3414)
12-31 11:44:35.792: W/System.err(7956): at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:3521)
12-31 11:44:35.792: W/System.err(7956): at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:3422)
12-31 11:44:35.792: W/System.err(7956): at android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:3578)
12-31 11:44:35.792: W/System.err(7956): at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3395)
12-31 11:44:35.792: W/System.err(7956): at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3445)
12-31 11:44:35.792: W/System.err(7956): at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3414)
12-31 11:44:35.792: W/System.err(7956): at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:3422)
12-31 11:44:35.792: W/System.err(7956): at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3395)
12-31 11:44:35.792: W/System.err(7956): at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:5535)
12-31 11:44:35.792: W/System.err(7956): at android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:5515)
12-31 11:44:35.792: W/System.err(7956): at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:5486)
12-31 11:44:35.792: W/System.err(7956): at android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent(ViewRootImpl.java:5615)
12-31 11:44:35.792: W/System.err(7956): at android.view.InputEventReceiver.dispatchInputEvent(InputEventReceiver.java:185)
12-31 11:44:35.792: W/System.err(7956): at android.os.MessageQueue.nativePollOnce(Native Method)
12-31 11:44:35.792: W/System.err(7956): at android.os.MessageQueue.next(MessageQueue.java:138)
12-31 11:44:35.792: W/System.err(7956): at android.os.Looper.loop(Looper.java:123)
12-31 11:44:35.792: W/System.err(7956): at android.app.ActivityThread.main(ActivityThread.java:5146)
12-31 11:44:35.792: W/System.err(7956): at java.lang.reflect.Method.invokeNative(Native Method)
12-31 11:44:35.792: W/System.err(7956): at java.lang.reflect.Method.invoke(Method.java:515)
12-31 11:44:35.792: W/System.err(7956): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:796)
12-31 11:44:35.792: W/System.err(7956): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:612)
12-31 11:44:35.792: W/System.err(7956): at dalvik.system.NativeStart.main(Native Method)
因此,GameActivityHandler
中的第125行是
mConnService.write(send.serialize());
导致这个例外。
那么如何序列化我的Ball
对象,发送它,在远程设备上接收它并再次反序列化它?
答案 0 :(得分:1)
那么如何序列化我的球
很简单:
import java.io.Serializable;
...
public class Ball implements Serializable
答案 1 :(得分:0)
添加以下内容
class Ball implements Serializable{
//Your code
}