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
Related
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.
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);
}
How do you use a method which is defined in another thread(not main) and in in a different class?Direct example is there is a ConnectedThread class in a bluetooth tutorial onAndroidDev
and in that class there is a write() method which is used to put something on a output stream of bluetooth.How can i use that method in the main activiy because i want to send an information by pressing a button?
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) { //how do i use this method in the ui(main) activity?
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) { }
}
}
Make sure the method you are trying to access from another class is a public method.
In this example the main activity calls a fragmentActivity and shows the fragment in the layout main activity. What you have to do is create a new button in the layout fragmentActivity and instantiate within the onViewCreated. After the button initializes the event within setupChat () method sending the sendMessage ("yourMessage") your information through parameter. Everything inside the fragment activity.
I would recommend using an eventbus such as EventBus or Otto. If you are changing the UI, you will need to register for the event and then run your code on the main thread with something like Activity.runOnUIThread(){}
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
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);
}