Problems with read() and readObject() - java

I try to develop a card game to play 1vs1 via Bluetooth. I have connected the devices, and now I have a problem: I want to send Objects throw the Bluetooth.
If I make only Objects, it works, if only Strings, it works.
But if I try to make both at the same time, I have problems.
/**
* 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;
// for Objects
private final ObjectInputStream mObjectInStream;
private final ObjectOutputStream mObjectOutStream;
public ConnectedThread(BluetoothSocket socket) {
if (D) Log.d(TAG, "create ConnectedThread");
mmSocket = socket;
InputStream tmpIn = null;
OutputStream tmpOut = null;
ObjectInputStream tmpObjIn = null;
ObjectOutputStream tmpObjOut = null;
// Get the BluetoothSocket input and output streams
try {
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
tmpObjOut = new ObjectOutputStream(socket.getOutputStream());
tmpObjOut.flush();
tmpObjIn = new ObjectInputStream(socket.getInputStream());
} catch (IOException e) {
Log.e(TAG, "temp sockets not created", e);
}
mmInStream = tmpIn;
mmOutStream = tmpOut;
mObjectOutStream = tmpObjOut;
mObjectInStream = tmpObjIn;
}
public void run() {
if (D) Log.i(TAG, "BEGIN mConnectedThread");
byte[] buffer = new byte[1024];
int bytes;
// Keep listening to the InputStream while connected
while (true) {
try {
// Read from the InputStream
bytes = mmInStream.read(buffer);
// Send the obtained bytes to the UI Activity
mHandler.obtainMessage(Constants.MESSAGE_READ, bytes, -1, buffer)
.sendToTarget();
} catch (IOException e) {
Log.e(TAG, "disconnected", e);
connectionLost();
// Start the service over to restart listening mode
BluetoothService.this.start();
break;
}
try {
// Send the obtained Object to the UI Activity
mHandler.obtainMessage(Constants.MESSAGE_READ_OBJECT, -1, -1, mObjectInStream.readObject())
.sendToTarget();
} catch (IOException e) {
Log.e(TAG, "disconnected", e);
connectionLost();
// Start the service over to restart listening mode
BluetoothService.this.start();
break;
} catch (ClassNotFoundException cn) {
Log.e(TAG, "Class not found", cn);
}
}
}
/**
* Write to the connected OutStream.
*
* #param buffer The bytes to write
*/
public void writeString(byte[] buffer) {
try {
mmOutStream.write(buffer);
// Share the sent message back to the UI Activity
mHandler.obtainMessage(Constants.MESSAGE_WRITE, -1, -1, buffer)
.sendToTarget();
} catch (IOException e) {
Log.e(TAG, "Exception during write", e);
}
}
/**
* Write an Object (Serializable) to the connected OutStream.
*
* #param object The object to write
*/
public void writeObject(Object object) {
try {
mObjectOutStream.writeObject(object);
// Share the sent message back to the UI Activity
// TODO hier unterscheiden zwischen Player und UnoKarte?
mHandler.obtainMessage(Constants.MESSAGE_WRITE_OBJECT, -1, -1, object)
.sendToTarget();
} catch (IOException e) {
Log.e(TAG, "Exception during write", e);
}
}
public void cancel() {
try {
mmSocket.close();
} catch (IOException e) {
Log.e(TAG, "close() of connect socket failed", e);
}
}
}
Error:
06-21 14:18:44.580 10941-11034/? E/BluetoothService﹕ disconnected
java.io.StreamCorruptedException: Wrong format: 0
at java.io.ObjectInputStream.corruptStream(ObjectInputStream.java:830)
at java.io.ObjectInputStream.readNonPrimitiveContent(ObjectInputStream.java:943)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:2262)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:2217)
at com.example.thm_wip1.uno.BluetoothService$ConnectedThread.run(BluetoothService.java:550)
line 550 is:mHandler.obtainMessage(Constants.MESSAGE_READ_OBJECT, -1, -1, mObjectInStream.readObject())
In the While(true) I have two try-catch, in first I try to read string and in the second my Object. How can I differentiate between String and Objects in the run-method?
I'm new to sockets, inputStream, outputStream..
If you need more details, I edit will edit my question.

StreamCorruptedException happens when you have header reading inconsistency in the device's internal consistency checks, in your case the consistency check is failing because you are trying to use multiple outputstreams and inputstreams, the first ones are defined in tmpout and tmpin and then you try to create ObjectOutputStreams and ObjectinputStreams from different outputstreams and inputstreams again. These cause header inconsistency.
The correct code that should fix this is as follows
try {
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
tmpObjOut = new ObjectOutputStream(tmpOut);
tmpObjOut.flush();
tmpObjIn = new ObjectInputStream(tmpIn);
} catch (IOException e) {
Log.e(TAG, "temp sockets not created", e);
}

Related

Android bluetooth send/receive a hashmap

I'm trying to send a hashmap from one device to another via bluetooth. I'm creating the hashmap like this, and then calling the connection threads writeObject method:
Map<String,String> subInfo = new HashMap<>();
subInfo.put("type", "subInfo");
subInfo.put("num", "1");
BTService.connectedThread.writeObject(subInfo);
My bluetooth service has the following class thats used to handle data transfer between devices in a background thread:
public static class ConnectedThread extends Thread {
private final BluetoothSocket mmSocket;
private final InputStream mmInStream;
private final OutputStream mmOutStream;
private final ObjectInputStream mmObjInStream;
private final ObjectOutputStream mmObjOutStream;
public ConnectedThread(BluetoothSocket socket) {
mmSocket = socket;
InputStream tmpIn = null;
OutputStream tmpOut = null;
ObjectInputStream tmpObjIn = null;
ObjectOutputStream tmpObjOut = null;
// Get the input and output streams, using temp objects because
// member streams are final
try {
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
tmpObjIn = new ObjectInputStream(socket.getInputStream());
tmpObjOut = new ObjectOutputStream(socket.getOutputStream());
} catch (IOException e) {
e.printStackTrace();
}
mmInStream = tmpIn;
mmOutStream = tmpOut;
mmObjInStream = tmpObjIn;
mmObjOutStream = tmpObjOut;
}
public void run() {
byte[] buffer = new byte[1024]; // buffer store for the stream
int bytes; // bytes returned from read()
// Keep listening to the InputStream until an exception occurs
while (!this.isInterrupted()) {
try {
// Read from the InputStream
bytes = mmInStream.read(buffer);
// Send the obtained bytes to the UI activity
mHandler.obtainMessage(Constants.MESSAGE_READ, bytes, -1, buffer)
.sendToTarget();
} catch (IOException e) {
e.printStackTrace();
break;
}
try {
//Read objects from ObjectInputStream
Object object = mmObjInStream.readObject();
// Send the obtained object to the UI activity
mHandler.obtainMessage(Constants.MESSAGE_READ_OBJECT, -1, 0, object)
.sendToTarget();
} catch (ClassNotFoundException | IOException e) {
e.printStackTrace();
}
}
}
/* Call this from the main activity to send data to the remote device */
public void write(byte[] bytes) {
try {
mmOutStream.write(bytes);
} catch (IOException e) {
e.printStackTrace();
}
}
public void writeObject(Object object) {
try {
mmObjOutStream.writeObject(object);
}catch(Exception e){
Log.e(TAG, "Error ObjectOutputStream: " + e.getLocalizedMessage());
}
}
/* Call this from the main activity to shutdown the connection */
public void cancel() {
try {
mmSocket.close();
this.interrupt();
} catch (IOException e) {
e.printStackTrace();
}
}
}
So when I call the writeObject method it should send the object down the Object output stream of the thread above.
On the other device, the code is similar. It just listens on the Object input stream for an object, once it has been found it sends a MESSAGE_READ_OBJECT message to my message handler in the main activity:
static class MessageHandler extends Handler {
private final WeakReference<MainActivity> mActivity;
MessageHandler(MainActivity activity) {
mActivity = new WeakReference<>(activity);
}
#Override
public void handleMessage(Message msg)
{
final MainActivity mainActivity = mActivity.get();
if (mainActivity == null) {
return;
}
switch(msg.what){
case Constants.MESSAGE_READ_OBJECT:
Object receivedObject = msg.obj;
//How should I pull out the hashmap here?
switch(type){
case "subInfo":
//do some things
break;
}
break;
}
}
}
What is the correct way to reassemble the hashmap in my message handler? I need to check the "type" key of the map and switch based on that, but as of right now I'm not sure how to get the map object back. The receivedObject object in my message handler doesn't seem to behave like a hashmap, and doesn't have the typical methods used for pulling out keys and values
Furthermore, instead of sending a generic Object over bluetooth, would it make more sense to directly send a Map type object?
Just direct convert
HashMap mHashmap = (HashMap) obj;
this is what I do ,
https://github.com/zhenbeiju/AndroidCommonUtil/blob/master/app/src/main/java/commanutil/utl/file/ObjUtil.java
useage: https://coding.net/u/zhenbeiju/p/javanlp_/git/blob/master/src/com/voice/common/util/nlp/Main.java

How to call write() function of ConnectedThread class of android bluetooth from main activity

i just want to know how to call the write function of the ConnectedThread class from main activity java file
public static class ConnectedThread extends Thread {
public final BluetoothSocket mmSocket;
private final InputStream mmInStream;
private final OutputStream mmOutStream;
public ConnectedThread(BluetoothSocket socket) {
mmSocket = socket;
InputStream tmpIn = null;
OutputStream tmpOut = null;
// Get the input and output streams, using temp objects because
// member streams are final
try {
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
} catch (IOException e) { }
mmInStream = tmpIn;
mmOutStream = tmpOut;
}
public void run() {
byte[] buffer = new byte[1024]; // buffer store for the stream
int bytes; // bytes returned from read()
// Keep listening to the InputStream until an exception occurs
while (true) {
try {
// Read from the InputStream
bytes = mmInStream.read(buffer);
// Send the obtained bytes to the UI activity
// mHandler.obtainMessage(2, bytes, -1, buffer).sendToTarget();
} catch (IOException e) {
break;
}
}
}
// Call this from the main activity to send data to the remote device
public void write(String m) {
try {
String msg = m;
mmOutStream.write(msg.getBytes());
} catch (Exception e)
{
e.printStackTrace();
}
}
/* Call this from the main activity to shutdown the connection */
public void cancel() {
try {
mmSocket.close();
} catch (IOException e) { }
}
}
The short answer is you cannot (and shouldn't) call it directly from an Activity callback or Handler tied to the main thread. This will cause the main thread of your app to block since you are making socket calls. Defer this to a background thread. There are many options you can use for this, such as HandlerThread, IntentService, AsyncTask or even the RxJava framework.

How to Use Classes - Bluetooth Thread

I'm trying to connect android and arduino and send data between them. I am following the guide http://developer.android.com/guide/topics/connectivity/bluetooth.html#ManagingAConnection
I think I vaguely understand how this works but I don't have a complete mastery of the basics so I am a bit stuck.
I am looking at the code for "connecting as a client":
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) { }
return;
}
// Do work to manage the connection (in a separate thread)
manageConnectedSocket(mmSocket);
}
/** Will cancel an in-progress connection, and close the socket */
public void cancel() {
try {
mmSocket.close();
} catch (IOException e) { }
}
}
and for "managing connection"
private class ConnectedThread extends Thread {
private final BluetoothSocket mmSocket;
private final InputStream mmInStream;
private final OutputStream mmOutStream;
public ConnectedThread(BluetoothSocket socket) {
mmSocket = socket;
InputStream tmpIn = null;
OutputStream tmpOut = null;
// Get the input and output streams, using temp objects because
// member streams are final
try {
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
} catch (IOException e) { }
mmInStream = tmpIn;
mmOutStream = tmpOut;
}
public void run() {
byte[] buffer = new byte[1024]; // buffer store for the stream
int bytes; // bytes returned from read()
// Keep listening to the InputStream until an exception occurs
while (true) {
try {
// Read from the InputStream
bytes = mmInStream.read(buffer);
// Send the obtained bytes to the UI activity
mHandler.obtainMessage(MESSAGE_READ, bytes, -1, buffer)
.sendToTarget();
} catch (IOException e) {
break;
}
}
}
/* Call this from the main activity to send data to the remote device */
public void write(byte[] bytes) {
try {
mmOutStream.write(bytes);
} catch (IOException e) { }
}
/* Call this from the main activity to shutdown the connection */
public void cancel() {
try {
mmSocket.close();
} catch (IOException e) { }
}
}
I basically copied the exact code and made new java files containing them.
I want to actually use these classes to send data so I paired the devices and then found the IDs like:
BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices();
if (pairedDevices.size() > 0)
{
// Loop through paired devices
for (BluetoothDevice device : pairedDevices)
{
if (device.getName().equals("HC-06"))
{
//NEED TO INSERT CODE HERE (I think...)
}
else
{
Intent intentneedsetting = new Intent(this, NeedSettingsActivity.class);
startActivity(intentneedsetting);
}
}
}
else
{
Intent intentneedsetting = new Intent(this, NeedSettingsActivity.class);
startActivity(intentneedsetting);
}
Any help regarding how to use these classes (ConnectThread/ConnectedThread) will be very appreciated!
I'm not sure what did you vaguley understood and what not but i'll try to explain the purpose of these classes in general..
ConnectThread - receives a bluetooth device that was discovered in the discovery stage (which is prior to connection obviously) gets the BT socket from the device and when run() is called it tries to connect to it.
if the connection succeeded - in the code it just says manageConnectedSocket(mmSocket); but that means that u should open a ConnectedThread for receiving and sending data through the socket.
ConnectedThread - as mentioned, is the thread for managing sending and receiving data. as you can see in the run() it constantly listens using a while(true) it calls read which is blocking - meaning "the thread is stuck there" until it receives incoming data.
When data is received it handles it with the mHandler which is also not implemented here, again you should just implement whatever you want to do with the data received.
The write method simply receives an array of bytes and writes it to the socket, note that this is also a blocking call therefore u should use it from another thread.
Hope this helps u understand

Android Threads and Asynchronus tasks

So I have a thread, lets call it connectedThread it receives data from a input stream (could be anything Bluetooth, wifi, usb serial etc), what I wanted to know is how do I send a interrupt to the thread which causes it hold on until a certain method in the same thread (connectedThread) is finished generating results. See the below pseudo code to help illustrate my point.
Connected Thread:
private class ConnectedThread extends Thread {
//Bluetooth socket just a example could be any input stream.
private final BluetoothSocket mmSocket;
private final InputStream mmInStream;
private final OutputStream mmOutStream;
public ConnectedThread(BluetoothSocket socket) {
mmSocket = socket;
InputStream tmpIn = null;
OutputStream tmpOut = null;
// Get the input and output streams, using temp objects because
// member streams are final
try {
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
} catch (IOException e) { }
mmInStream = tmpIn;
mmOutStream = tmpOut;
}
public void run() {
byte[] buffer; // buffer store for the stream
int bytes; // bytes returned from read()
// Keep listening to the InputStream until an exception occurs
while (true) {
try {
// Read from the InputStream
// Arbitrary size for input stream data buffer.
buffer = new byte[3];
//Send a arbitrary command for device to respond
mmOutStream.write(255);
bytes = mmInStream.read(buffer,0,buffer.length);
/* This is where I want to not hard code a time out but in fact,
* wait for mmInStream.read(buffer,0,buffer.length);
* to finish then immediately proceed
*/
Thread.sleep(87);
// Send the obtained bytes to the message handler
mHandler.obtainMessage(MESSAGE_READ,buffer).sendToTarget();
}
catch (IOException e) {
break;
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
/* Call this from the main activity to send data to the remote device */
public void write(byte[] bytes) {
try {
mmOutStream.write(bytes);
} catch (IOException e) { }
}
}
}
Summary
So as I suggested in the code comments above. I want the current executing thread to wait for the input stream data to finish filling up the buffer then immediately send the results to the message handler. In particular I do not want to use the Thread.sleep() command as this slows down the process. I have already read the following page intensely but haven't found a solution to my problem.

how to call thread method

So I am quite new to java so be gentle.
I am trying to connect two phones by bluetooth. I created a socket but how should I use it? I mean, bluetooth tutorial says that I should call public void write(byte[] bytes) to send data, but how? I created button, assigned "onClick" method but what then? how should I call method that is in ConnectedThread form UI thread? Here is example from tutorial.
private class ConnectedThread extends Thread {
private final BluetoothSocket mmSocket;
private final InputStream mmInStream;
private final OutputStream mmOutStream;
public ConnectedThread(BluetoothSocket socket) {
mmSocket = socket;
InputStream tmpIn = null;
OutputStream tmpOut = null;
Message msg = mainHandler.obtainMessage();
Bundle bundle = new Bundle();
String btnTxt = "Socket aquizaired";
bundle.putString("myKey", btnTxt);
msg.setData(bundle);
mainHandler.sendMessage(msg);
// Get the input and output streams, using temp objects because
// member streams are final
try {
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
} catch (IOException e) { }
mmInStream = tmpIn;
mmOutStream = tmpOut;
}
public void run() {
byte[] buffer = new byte[1024]; // buffer store for the stream
int bytes; // bytes returned from read()
// Keep listening to the InputStream until an exception occurs
while (true) {
try {
// Read from the InputStream
bytes = mmInStream.read(buffer);
// Send the obtained bytes to the UI activity
// mHandler.obtainMessage(MESSAGE_READ, bytes, -1, buffer).sendToTarget();
} catch (IOException e) {
break;
}
}
}
/* Call this from the main activity to send data to the remote device */
public void write(byte[] bytes) {
try {
mmOutStream.write(bytes);
} catch (IOException e) { }
}
/* Call this from the main activity to shutdown the connection */
public void cancel() {
try {
mmSocket.close();
} catch (IOException e) { }
}
}
and in the UI thread I have something like
private void sendSms (){ // method assigned to button "onClick"
// i want to send some text here, like "hello" or something...
//???????????????????????????
}
The examples in the android sdk have a very good bluetooth chat example, you should have a look at it.
public void write(byte[] out) {
ConnectedThread r;
synchronized (this) {
if (mState != STATE_CONNECTED) return;
r = mConnectedThread;
}
r.write(out);
}

Categories