I don't understand the best way to use this class that the official documentation expose.
They say
1)Get the InputStream and OutputStream that handle transmissions through
the socket using getInputStream() and getOutputStream(), respectively.
2)Read and write data to the streams using read(byte[]) and
write(byte[]).
and give this example
public class MyBluetoothService {
private static final String TAG = "MY_APP_DEBUG_TAG";
private Handler mHandler; // handler that gets info from Bluetooth service
// Defines several constants used when transmitting messages between the
// service and the UI.
private interface MessageConstants {
public static final int MESSAGE_READ = 0;
public static final int MESSAGE_WRITE = 1;
public static final int MESSAGE_TOAST = 2;
// ... (Add other message types here as needed.)
}
private class ConnectedThread extends Thread {
private final BluetoothSocket mmSocket;
private final InputStream mmInStream;
private final OutputStream mmOutStream;
private byte[] mmBuffer; // mmBuffer store for the stream
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();
} catch (IOException e) {
Log.e(TAG, "Error occurred when creating input stream", e);
}
try {
tmpOut = socket.getOutputStream();
} catch (IOException e) {
Log.e(TAG, "Error occurred when creating output stream", e);
}
mmInStream = tmpIn;
mmOutStream = tmpOut;
}
public void run() {
mmBuffer = new byte[1024];
int numBytes; // bytes returned from read()
// Keep listening to the InputStream until an exception occurs.
while (true) {
try {
// Read from the InputStream.
numBytes = mmInStream.read(mmBuffer);
// Send the obtained bytes to the UI activity.
Message readMsg = mHandler.obtainMessage(
MessageConstants.MESSAGE_READ, numBytes, -1,
mmBuffer);
readMsg.sendToTarget();
} catch (IOException e) {
Log.d(TAG, "Input stream was disconnected", e);
break;
}
}
}
// Call this from the main activity to send data to the remote device.
public void write(byte[] bytes) {
try {
mmOutStream.write(bytes);
// Share the sent message with the UI activity.
Message writtenMsg = mHandler.obtainMessage(
MessageConstants.MESSAGE_WRITE, -1, -1, mmBuffer);
writtenMsg.sendToTarget();
} catch (IOException e) {
Log.e(TAG, "Error occurred when sending data", e);
// Send a failure message back to the activity.
Message writeErrorMsg =
mHandler.obtainMessage(MessageConstants.MESSAGE_TOAST);
Bundle bundle = new Bundle();
bundle.putString("toast",
"Couldn't send data to the other device");
writeErrorMsg.setData(bundle);
mHandler.sendMessage(writeErrorMsg);
}
}
// Call this method from the main activity to shut down the connection.
public void cancel() {
try {
mmSocket.close();
} catch (IOException e) {
Log.e(TAG, "Could not close the connect socket", e);
}
}
}
}
I have the rest of the code that following the documentation in the main activity and i need to manage the connection now with this class...
Now i adapt the code in the main activity (copy the private class ConnectedThread extends Threads in the MainActivity) but if someone can explain to me the best usage of this class it's better for me.
Thanks
Related
I Have a code that connects to a bluetooth device, opens a bluetooth socket that communicates with a running thread which operates functions running in main activity.
I would like to move all the connecting sequence to another activity, and then operate the thread from the main one as done now. The problem is they are all connected.
I would like to have the option of sending a message between these activities(meaning remaining the socket operating from the other activity), i.e this message:
mHandler.obtainMessage(CONNECTING_STATUS, 1, -1, name)
.sendToTarget();
because it is impossible to pass handler between activities I don't know how/if possible to do so.
What is the best way of doing such a thing?
added part of the code.
Thanks.
mHandler = new Handler(){
public void handleMessage(android.os.Message msg){
if(msg.what == MESSAGE_READ){
String readMessage = null;
try {
readMessage = new String((byte[]) msg.obj, "UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
RxMessage = readMessage.split(" ");
if (sH.isStringInCorrectOrder(RxMessage,Weight))
populateListView(RxMessage);
mReadBuffer.setText(readMessage);
}
if(msg.what == CONNECTING_STATUS){
if(msg.arg1 == 1)
mBluetoothStatus.setText("Connected to Device: " + (String)(msg.obj));
else
mBluetoothStatus.setText("Connection Failed");
}
}
};
private void connectBT (){
mBluetoothStatus.setText("Connecting...");
// Get the device MAC address, which is the last 17 chars in the View
final String address = "98:D3:31:30:39:75";
final String name = "HC-06";
// Spawn a new thread to avoid blocking the GUI one
new Thread()
{
public void run() {
boolean fail = false;
BluetoothDevice device = mBTAdapter.getRemoteDevice(address);
try {
mBTSocket = createBluetoothSocket(device);
} catch (IOException e) {
fail = true;
Toast.makeText(getBaseContext(), "Socket creation failed", Toast.LENGTH_SHORT).show();
}
// Establish the Bluetooth socket connection.
try {
mBTSocket.connect();
} catch (IOException e) {
try {
fail = true;
mBTSocket.close();
mHandler.obtainMessage(CONNECTING_STATUS, -1, -1)
.sendToTarget();
} catch (IOException e2) {
//insert code to deal with this
Toast.makeText(getBaseContext(), "Socket creation failed", Toast.LENGTH_SHORT).show();
}
}
if(fail == false) {
mConnectedThread = new ConnectedThread(mBTSocket);
mConnectedThread.start();
mHandler.obtainMessage(CONNECTING_STATUS, 1, -1, name)
.sendToTarget();
}
}
}.start();
}
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.available();
if(bytes != 0) {
SystemClock.sleep(100); //pause and wait for rest of data. Adjust this depending on your sending speed.
bytes = mmInStream.available(); // how many bytes are ready to be read?
bytes = mmInStream.read(buffer, 0, bytes); // record how many bytes we actually read
mHandler.obtainMessage(MESSAGE_READ, bytes, -1, buffer)
.sendToTarget(); // Send the obtained bytes to the UI activity
}
} catch (IOException e) {
e.printStackTrace();
break;
}
}
}
/* Call this from the main activity to send data to the remote device */
public void write(String input) {
byte[] bytes = input.getBytes(); //converts entered String into 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) { }
}
}
Just declare mHandler as static and you can access it from all other activities. This will create a small temporary memory leak, but don't worry about it.
stuck in One Issue ,
I am using BluetoothSocket class, I am sending and receiving data with the help of input and output streams.
when App receives large amount of data from input stream, I am killing my app forcefully and after it I am again restarting my app, but InputStream returns me previous data, which is not needed anymore.how to discard that old data?
has Anyone Some Solution for this Issue?
Following is my source code:
public class MyBluetoothService {
private static final String TAG = "MY_APP_DEBUG_TAG";
private Handler mHandler; // handler that gets info from Bluetooth service
// Defines several constants used when transmitting messages between the
// service and the UI.
private interface MessageConstants {
public static final int MESSAGE_READ = 0;
public static final int MESSAGE_WRITE = 1;
public static final int MESSAGE_TOAST = 2;
// ... (Add other message types here as needed.)
}
private class ConnectedThread extends Thread {
private final BluetoothSocket mmSocket;
private final InputStream mmInStream;
private final OutputStream mmOutStream;
private byte[] mmBuffer; // mmBuffer store for the stream
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();
} catch (IOException e) {
Log.e(TAG, "Error occurred when creating input stream", e);
}
try {
tmpOut = socket.getOutputStream();
} catch (IOException e) {
Log.e(TAG, "Error occurred when creating output stream", e);
}
mmInStream = tmpIn;
mmOutStream = tmpOut;
}
public void run() {
mmBuffer = new byte[1024];
int numBytes; // bytes returned from read()
// Keep listening to the InputStream until an exception occurs.
while (true) {
try {
// Read from the InputStream.
numBytes = mmInStream.read(mmBuffer);
// Send the obtained bytes to the UI activity.
Message readMsg = mHandler.obtainMessage(
MessageConstants.MESSAGE_READ, numBytes, -1,
mmBuffer);
readMsg.sendToTarget();
} catch (IOException e) {
Log.d(TAG, "Input stream was disconnected", e);
break;
}
}
}
// Call this from the main activity to send data to the remote device.
public void write(byte[] bytes) {
try {
mmOutStream.write(bytes);
// Share the sent message with the UI activity.
Message writtenMsg = mHandler.obtainMessage(
MessageConstants.MESSAGE_WRITE, -1, -1, mmBuffer);
writtenMsg.sendToTarget();
} catch (IOException e) {
Log.e(TAG, "Error occurred when sending data", e);
// Send a failure message back to the activity.
Message writeErrorMsg =
mHandler.obtainMessage(MessageConstants.MESSAGE_TOAST);
Bundle bundle = new Bundle();
bundle.putString("toast",
"Couldn't send data to the other device");
writeErrorMsg.setData(bundle);
mHandler.sendMessage(writeErrorMsg);
}
}
// Call this method from the main activity to shut down the connection.
public void cancel() {
try {
mmSocket.close();
} catch (IOException e) {
Log.e(TAG, "Could not close the connect socket", e);
}
}
}
}
// Keep listening to the InputStream until an exception occurs
The problem is here. You should keep reading from the stream until end of stream or an exception occurs. You need to break out of the read loop if read() returns -1.
At present you are reading beyond end of stream, and ignoring the condition altogether, so of course the data that was in the buffer on the last successful read is still there.
For your application to keep seeing that data, you must also be ignoring the read count and assuming the buffer was filled, which also is invalid.
I think you should close the socket to manage the bug.
I recommend you to do this in finalizer like the code below.
private class ConnectedThread extends Thread
{
private final BluetoothSocket mmSocket;
private final InputStream mmInStream;
private final OutputStream mmOutStream;
private byte[] mmBuffer; // mmBuffer store for the stream
#override
protected void finalize() throws Throwable
{
try
{
cancel();
}
finally
{
super.finalize();
}
}
...
Also as I mentioned in comment, it is safer to close every streams before closing the socket.
So, try this cancel() method.
// Call this method from the main activity to shut down the connection.
public void cancel()
{
try {
mmInStream.close();
} catch( NullPointerException | IOException e) {}
try {
mmOutStream.close();
} catch( NullPointerException | IOException e) {}
try
{
mmSocket.close();
} catch (IOException e) {
Log.e(TAG, "Could not close the connect socket", e);
}
}
And more information about finalize method.
EDIT: bold ones are important than other suggestions.
Reading comments of EJP I understood why your app stops when you get large data : you maybe have to clear buffers before calling read(). And he says that finalizer can happen not to be called by system (I don't know why).
How about breaking the loop when the read() returned -1?
And just now I found a helpful link about proper method to read a stream. I hope it helped.
Code cited from the link
private String extract(InputStream inputStream) throws IOException
{
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int read = 0;
while ((read = inputStream.read(buffer, 0, buffer.length)) != -1) {
baos.write(buffer, 0, read);
}
baos.flush();
return new String(baos.toByteArray(), "UTF-8");
}
Also
Though the finalizer may be able not to be called by system closing streams before closing sockets is safer (I read some SO threads before).
I have a frustrating issue, that being my serial Bluetooth receiving code does not always receive the data from it's connection. Most of the time, it works perfectly, but sometimes after connection, it does not receive any data even though I can verify the connection is there, and the other device is sending the data. My receiving code is below:
/**
* Created by tvanderpuy on 12/1/2016.
* Handles communication with BT device
*/
private class ConnectedThread extends Thread {
private final BluetoothSocket mmSocket;
private final InputStream mmInStream;
private final OutputStream mmOutStream;
private final BufferedReader bufferedReader;
public ConnectedThread(BluetoothSocket socket) {
Log.d(TAG, "create ConnectedThread");
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) {
Log.e(TAG, "temp sockets not created", e);
}
mmInStream = tmpIn;
mmOutStream = tmpOut;
// Set up buffered reader
bufferedReader = new BufferedReader(new InputStreamReader(mmInStream));
}
public void run() {
Log.i(TAG, "BEGIN mConnectedThread");
byte[] buffer = new byte[1024]; // buffer store for the stream
int bytes; // bytes returned from read()
String cmd;
// Keep listening to the InputStream until an exception occurs
while (mState == STATE_CONNECTED) {
try {
// Wait for new line for buffered reader
cmd = bufferedReader.readLine();
// Send the obtained bytes to the UI activity
if (!cmd.isEmpty())
mHandler.obtainMessage(MESSAGE_READ, cmd.getBytes().length, -1, cmd.getBytes())
.sendToTarget();
Log.v(TAG, "Command: " + cmd);
} catch (IOException e) {
Log.e(TAG, "disconnected", e);
connectionLost();
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) {
}
}
}
}
Please let me know if you have any insight into this.
Thank you,
Tom
I'm trying to create bluetooth application, using this tutorial:
https://developer.android.com/guide/topics/connectivity/bluetooth.html
There is class ConnectedThread:
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) { }
}
}
Comment says I need to call write() method from main activity, but there is actually no instance of ConnectedThread class, it is just started from another class. How can I use this method?
EDIT1:
I see why I can't use it that way.
It doesn't work, because ConnectedThread is defined and declared at the point in the program and when program leaves it, it no longer exists, right? So, should I define object of ConnectedThread visible in whole activity and just define it in Connect thread. Instead:
ConnectedThread mConnectedThread = new ConnectedThread(mmSocket);
mConnectedThread.start();
I could use:
mConnectedThread = new ConnectedThread(mmSocket);
mConnectedThread.start();
Right?
I have an InputStream which runs on a thread and reads any data which is passed over the network. My question is- how do I distinguish between the bytes received by the InputStream object? e.g. if the bytes received point to a Car object, do something, if bytes received point to a Person object, do something else.
Thanks.
EDIT: here's a snippet of my code. does it seem fine? sorry, im new to network programming.
private class ConnectedThread extends Thread {
private final BluetoothSocket mmSocket;
private final InputStream mmInStream;
private final ObjectOutputStream mmObjOutStream;
public ConnectedThread(BluetoothSocket socket) {
Log.d(TAG, "create ConnectedThread");
mmSocket = socket;
InputStream tmpIn = null;
ObjectOutputStream tmpOut = null;
// Get the BluetoothSocket input and output streams
try {
tmpIn = socket.getInputStream();
tmpOut = new ObjectOutputStream(socket.getOutputStream());
} catch (IOException e) {
Log.e(TAG, "temp sockets not created", e);
}
mmInStream = tmpIn;
mmObjOutStream = 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 {
// Read from the InputStream
bytes = mmInStream.read(buffer);
Log.i(TAG, "PERFORMING MESSAGE READ");
// Send the obtained bytes to the UI Activity
mHandler.obtainMessage(GameboardResourceActivity.MESSAGE_READ, bytes, -1, buffer)
.sendToTarget();
} catch (IOException e) {
Log.e(TAG, "disconnected", e);
connectionLost();
break;
}
}
}
/**
* Write to the connected OutStream.
* #param buffer The bytes to write
*/
public void write(CardResource buffer) {
try {
mmObjOutStream.writeObject(buffer);
System.out.println("Reached here at least........");
// Share the sent message back to the UI Activity
mHandler.obtainMessage(GameboardResourceActivity.MESSAGE_WRITE, -1, -1, buffer)
.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);
}
}
}
Well you do have to know what your application protocol is to understand it. It sounds like the other end is using Serialization, which you need to read up. See the Javadoc for ObjectOutputStream and ObjectInputStream. What you need is ObjectInputStream.readObject(), if this supposition is correct. If it isn't, you will just have to find out what they are sending you and proceed accordingly, probably with a DataInputStream to handle the various datatypes.
You can pass yor sockets input stream directly into the constructor for ObjectInputStream:
ObjectInputStream inputStream = new ObjectInputStream(socket.getInputStream());
while ((obj = inputStream.readObject()) != null) {
if (obj instanceof Person) {
System.out.println(((Person)obj).toString());
}
}
EDIT
As the comments state this will prematurely exit if you pass a null value into your ObjectOutputStream on the other end. Its best to guard against this, null values are never a good thing to receive unexpectedly.