I cannot cancel my thread in Android - android

I am developing an app that communicated with Arduino via bluetooth, however, I dont know why I cannot cancel the thread which responsible for the bluetooth inputstream.
public class mainclass extends Activity{
BluetoothSocket scSocket = AnotherClass.btSocket;
SendReceiveBytes sendReceiveBT;
Thread th;
protected void onCreate(Bundle savedInstanceState) {
.
.
sendReceiveBT = new SendReceiveBytes(scSocket);
th = new Thread(sendReceiveBT);
th.start();
.
.
sendReceiveBT.stop=true;
Log.e(TAG, "Request sent");
.
.
}
}
public class SendReceiveBytes implements Runnable {
public static final int MESSAGE_WRITE = 1;
public static final int MESSAGE_READ = 2;
String readMessage="";
private BluetoothSocket btSocket;
private InputStream btInputStream = null;
private OutputStream btOutputStream = null;
public boolean stop=false;
public boolean stopped=false;
String TAG = "SendReceiveBytes";
public SendReceiveBytes(BluetoothSocket socket) {
btSocket = socket;
try {
btInputStream = btSocket.getInputStream();
btOutputStream = btSocket.getOutputStream();
}
catch (IOException streamError) {
Log.e(TAG, "Error when getting input or output Stream");
}
}
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 (!stop) {
try {
// Read from the InputStream
bytes = btInputStream.read(buffer);
// Send the obtained bytes to the UI activity
byte[] readBuf = (byte[]) buffer;
// construct a string from the valid bytes in the buffer
readMessage = new String(readBuf, 0, bytes);
}
catch (IOException e) {
Log.e(TAG, "Error reading from btInputStream");
break;
}
}
Log.e(TAG, "Quit");
stopped=true;
}
}
In the LogCat, the tag with "Request sent" is shown which means I already set the "stop" to true, however, the tag with "Quit" never show up.

You could try to override the stop()-method, which set stop-flag to true. Also make sure to close your streams.

Related

How to solve delay in Inputstream.read() in android?

I am working on a Bluetooth multiplayer game project.I followed the android Bluetooth overview https://developer.android.com/guide/topics/connectivity/bluetooth strictly.I used the following code to read and write data:-
public class MyBluetoothService {
private static final String TAG = "MY_APP_DEBUG_TAG";
private Handler handler; // 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 = handler.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 = handler.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 =
handler.obtainMessage(MessageConstants.MESSAGE_TOAST);
Bundle bundle = new Bundle();
bundle.putString("toast",
"Couldn't send data to the other device");
writeErrorMsg.setData(bundle);
handler.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);
}
}
}
}
For writing data I am using the following code:-
String[] myString={"HI!","How Are YOU"};
mConnected.write(Arrays.toString(myString).getBytes());
But I see that inputstream.read() is receiving data quite late after another device is sending the data.I found some questions regarding this,but none of them seem to provide a satisfactory answer.Any suggestion will be highly helpful.
After
mmOutStream.write(bytes);
try to call:
mmOutStream.flush();
this will cause the bytes to be sent immediately.
https://docs.oracle.com/javase/7/docs/api/java/io/OutputStream.html#flush()

Android Bluetooth RFCOMM can't receive strings

i'm trying to exchange Strings between two android devices. I'm able to establishe a RFCOMM connection and sending a String. But my APP cant receive it. After days of trail and error and searching on the internet i hope somebody can help me:
Thats my code so far:
public class MainActivity extends AppCompatActivity {
BluetoothAdapter bluetoothAdapter;
protected static final int SUCCESS_CONNECT = 0;
protected static final int MESSAGE_READ = 1;
Handler mHandler = new Handler(){
#Override
public void handleMessage(Message msg) {
Log.i("MAC", "in handler");
super.handleMessage(msg);
switch(msg.what){
case SUCCESS_CONNECT:
// DO something
ConnectedThread connectedThread = new ConnectedThread((BluetoothSocket)msg.obj);
connectedThread.run();
Toast.makeText(getApplicationContext(), "CONNECT", Toast.LENGTH_LONG).show();
String s = "successfully connected";
connectedThread.write(s.getBytes());
Log.i("MAC", "connected");
break;
case MESSAGE_READ:
byte[] readBuf = (byte[])msg.obj;
String string = new String(readBuf);
Toast.makeText(getApplicationContext(), string, Toast.LENGTH_LONG).show();
break;
}
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_ACL_CONNECTED);
registerReceiver(mReceiver,filter);
}
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if (action.equals(BluetoothDevice.ACTION_ACL_CONNECTED)){
BluetoothDevice device = intent
.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
Log.i("MAC","Connect to : " +device.getAddress());
ConnectingThread ct = new ConnectingThread(device);
ct.start();
}
}
};
private class ConnectingThread extends Thread {
private final BluetoothSocket bluetoothSocket;
private final BluetoothDevice bluetoothDevice;
public ConnectingThread(BluetoothDevice device) {
BluetoothSocket temp = null;
bluetoothDevice = device;
// Get a BluetoothSocket to connect with the given BluetoothDevice
try {
temp = bluetoothDevice.createRfcommSocketToServiceRecord(UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"));
} catch (IOException e) {
e.printStackTrace();
}
bluetoothSocket = temp;
}
public void run() {
// Cancel any discovery as it will slow down the connection
bluetoothAdapter.cancelDiscovery();
try {
// This will block until it succeeds in connecting to the device
// through the bluetoothSocket or throws an exception
bluetoothSocket.connect();
} catch (IOException connectException) {
connectException.printStackTrace();
try {
bluetoothSocket.close();
} catch (IOException closeException) {
closeException.printStackTrace();
}
}
// Code to manage the connection in a separate thread
mHandler.obtainMessage(SUCCESS_CONNECT, bluetoothSocket).sendToTarget();
/*
manageBluetoothConnection(bluetoothSocket);
*/
}
// Cancel an open connection and terminate the thread
public void cancel() {
try {
bluetoothSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
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; // 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
buffer = new byte[1024];
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) { }
}
}
}

Textview values does not update when data received from Arduino

I receiving 3 data from Arduino and the data just keep coming in. My problem is the data doesn't update to the new received values.
Here is the screenshot from the logcat:
So D/BPM is the value in the textview 68
D/SPo2 is the value in the textview 99
D/temp is the value in textview 28.0
D/read: 71 is for BPM 99 is for SPo2 and 28.11 is for temp.
But the textview values just stuck at 68 99 and 28.0. :(
Here are my code for the Android part:
public class Bluetooth_dataDisplay extends Activity {
//declaration
BluetoothAdapter mAdapter;
private ArrayAdapter adapter;
TextView myLabel;
TextView myLabel1;
TextView myLabel2;
Thread workerThread;
byte[] readBuffer;
int readBufferPosition;
volatile boolean stopWorker;
private ListView listview;
private BluetoothSocket bluetoothSocket;
private ConnectedThread mConnectedThread;
final int handlerState = 0;
private StringBuilder recDataString = new StringBuilder();
private final Handler mHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
case Constants.MESSAGE_READ:
byte[] readBuf = (byte[]) msg.obj;
// construct a string from the valid bytes in the buffer
String readMessage = new String(readBuf, 0, msg.arg1);
recDataString.append(readMessage);
Log.d("read",readMessage);
if (recDataString.charAt(0) == '#')
{
String BPM = recDataString.substring(1,3);
String SPO2= recDataString.substring(3,5);
String Temp= recDataString.substring(5,9);
Log.d("BPM", BPM);
Log.d("SPO2", SPO2);
Log.d("Temp", Temp);
myLabel.setText("BPM" + " " + BPM);
myLabel1.setText("SPO2" +" "+ SPO2);
myLabel2.setText("Temp"+" " + Temp);
}
//recDataString.delete(0, recDataString.length());
break;
}
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.bluetooth_datadisplay);
myLabel = (TextView)findViewById(R.id.label);
myLabel1 = (TextView)findViewById(R.id.label1);
myLabel2= (TextView)findViewById(R.id.label2);
}//end oncreate
#Override
public void onResume() {
super.onResume(); // Always call the superclass method first
//Get MAC address from BluetoothActivity using intent and Extra
String MAC = getIntent().getStringExtra("MAC");
//must declare every time on a new activity if not will result in null error
mAdapter = BluetoothAdapter.getDefaultAdapter();
//create device and set the MAC address
BluetoothDevice bluetoothDevice = mAdapter.getRemoteDevice(MAC);
// Initiate a connection request in a separate thread
ConnectingThread t = new ConnectingThread(bluetoothDevice);
t.start();
}
#Override
public void onPause()
{
super.onPause();
try {
bluetoothSocket.close();
} catch (IOException e) {
Log.e("error", "terminate thread");
e.printStackTrace();
}
}
/**
* 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(BluetoothSocket socket, BluetoothDevice device) {
// Start the thread to manage the connection and perform transmissions
mConnectedThread = new ConnectedThread(socket);
mConnectedThread.start();
}
private class ConnectingThread extends Thread {
private final BluetoothSocket bluetoothSocket;
private final BluetoothDevice bluetoothDevice;
public ConnectingThread(BluetoothDevice device) {
BluetoothSocket temp = null;
bluetoothDevice = device;
// Get a BluetoothSocket to connect with the given BluetoothDevice
try {
temp = bluetoothDevice.createRfcommSocketToServiceRecord(uuid);
} catch (IOException e) {
e.printStackTrace();
}
bluetoothSocket = temp;
}
public void run() {
// Cancel any discovery as it will slow down the connection
mAdapter.cancelDiscovery();
try {
// This will block until it succeeds in connecting to the device
// through the bluetoothSocket or throws an exception
bluetoothSocket.connect();
} catch (IOException connectException) {
connectException.printStackTrace();
try {
bluetoothSocket.close();
} catch (IOException closeException) {
closeException.printStackTrace();
}
}
// Code to manage the connection in a separate thread
connected(bluetoothSocket, bluetoothDevice);
}
// Cancel an open connection and terminate the thread
public void cancel() {
try {
bluetoothSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 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 bluetoothSocket;
private final InputStream mmInputStream;
//private final OutputStream mmOutputStream;
public ConnectedThread(BluetoothSocket socket) {
bluetoothSocket = socket;
InputStream tmpIn = null;
OutputStream tmpOut = null;
// Get the BluetoothSocket input and output streams
try {
tmpIn = socket.getInputStream();
//tmpOut = socket.getOutputStream();
} catch (IOException e) {
}
mmInputStream = tmpIn;
//mmOutputStream = tmpOut;
}//endofConnectedThread(BluetoothSocket socket)
public void run() {
byte[] buffer = new byte[1024];
int bytes;
// Keep listening to the InputStream while connected
while (true) {
try {
// Read from the InputStream
bytes = mmInputStream.read(buffer);
// Send the obtained bytes to the UI Activity
mHandler.obtainMessage(Constants.MESSAGE_READ, bytes, -1, buffer)
.sendToTarget();
} catch (IOException e) {
break;
}
}
}//end of void run
}//end of connectecthread
}
Because Arduino will be sending in data eg #719928.11 so the index will be in this order (0123456789)
Which is why I did it this way to extract the data:
if (recDataString.charAt(0) == '#')
{
String BPM = recDataString.substring(1,3);
String SPO2= recDataString.substring(3,5);
String Temp= recDataString.substring(5,9);
Log.d("BPM", BPM);
Log.d("SPO2", SPO2);
Log.d("Temp", Temp);
myLabel.setText("BPM" + " " + BPM);
myLabel1.setText("SPO2" +" "+ SPO2);
myLabel2.setText("Temp"+" " + Temp);
}
Just to add more details regarding the data:
BPM and SPO2 are in int (pulse oximeter)
Temp is in float format
So if my pulse oximeter is not on. My data look like this #0028.28 where the first 0 is BPM and the second 0 is SPO2. 28.28 is temp
So if the pulse oximeter is on. My data look like this #669928.28 where 66 is BPM and 99 is SPO2. 28.28 is temp. Below is data displayed in Arduino serial monitor:
Try this
1 .
replace
private StringBuilder recDataString = new StringBuilder();
with this one
private String recDataString = "";
2 . replace
recDataString.append(readMessage);
with this one
recDataString = readMessage ;
Data Parsing for different-2 situations :
if(recDataString.lenth > 0){
//If Oxiometer is OFF
if(recDataString.startsWith(#00) && recDataString.length == 8){
//Do Parsing here #0028.14
String BPM = "0";
String SPO2= "0";
String temp = recDataString.split("00")[1];
myLabel.setText("BPM" + " " + BPM);
myLabel1.setText("SPO2" +" "+ SPO2);
myLabel2.setText("Temp"+" " + Temp);
}
//If Oxiometer is on
if(recDataString.startsWith(#) && recDataString.length() == 10){
//Do Parsing here #779928.08
String BPM = recDataString.substring(1,3);
String SPO2= recDataString.substring(3,5);
String temp = recDataString.substring(5,recDataString.lenth());
myLabel.setText("BPM" + " " + BPM);
myLabel1.setText("SPO2" +" "+ SPO2);
myLabel2.setText("Temp"+" " + Temp);
}
//If String contains # only .
if(recDataString.startsWith(#) && recDataString.length == 1){
//Do nothing or you can decide
}
}
Before recDataString.append(readMessage); try to reset the recDataString first, like this:
recDataString.setLength(0);
Because if it does not reset, it will continue append new strings:
#689928.0
#689928.06899719928.11 ...

How can I receive the data stream from Bluetooth and add it to LinkedHashMap<>?

I am beginner in Android and I have a problem with receiving the data stream sent from Bluetooth by RfcommSocket and add it to LinkedHashMap ? I use the code below but it doesn't work and I don't know, how can I deal with it?
public class BluetoothConnectionThread extends Thread{
public static final int MESSAGE_READ = 9999;
private final BluetoothDevice btDevice;
private BluetoothSocket btSocket;
private InputStream inStream;
private OutputStream outStream;
Map<Integer, Byte[]> linkedHashMap = new LinkedHashMap<Integer, Byte[]>();
private static UUID uuid = UUID.fromString("ae3fdfc0-8bd1-11e5-8994-feff819cdc9f");
private final Handler mHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
String address = null;
switch (msg.what) {
case MESSAGE_READ:
byte[] readBuf = (byte[]) msg.obj;
String readMessage = new String(readBuf, 0, msg.arg1);
break;
}
}
};
public BluetoothConnectionThread(BluetoothDevice device) {
this.btDevice = device;
try
{
btSocket = this.btDevice.createRfcommSocketToServiceRecord(uuid);
} catch (IOException ex) {
btSocket = null;
}
}
public void ConnectedThread(BluetoothSocket socket) {
this.btSocket = socket;
InputStream tmpIn = null;
OutputStream tmpOut = null;
try {
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
} catch (IOException e) { }
inStream = tmpIn;
outStream = tmpOut;
}
public void run() {
BluetoothAdapter.getDefaultAdapter().cancelDiscovery();
byte[] buffer = new byte[32];
int bytes;
try {
btSocket.connect();
bytes = inStream.read(buffer);
mHandler.obtainMessage(MESSAGE_READ, bytes, -1, buffer).sendToTarget();
} catch(IOException ex) {
try {
btSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public void write(byte[] bytes) {
try {
outStream.write(bytes);
} catch (IOException e) { }
}
public void cancel() {
try {
btSocket.close();
} catch(IOException e) {
e.printStackTrace();
}
}
}
In answer to why it's not working, you are not adding any values to the hashmap.
Depending on how you are selecting the key Integer, I have just used a static int for demonstration purposes, but this isn't the best way to go about this. If this is how you are generating the key I would suggest a List.
static int intKey = 0;
In your case MESSAGE_READ:
byte[] readBuf = (byte[]) msg.obj;
linkedHashMap .put(intKey, readBuf)
intKey++;
I suggest you examine other ways of doing this, or as you do not seem to have a clear idea of how or why you are using a linked hash map.

Updating an Activity using Handlers

The following code has a thread that is responsible of connection to a server using a a specific socket. The idea of connecting works fine (in a separate thread). After the connection is established, I tried to update the main Activity using a Handler but it wouldn't updated!
Here is my code for the background thread:
public class SocketThread extends Thread {
private final Socket socket;
private final InputStream inputStream;
private final OutputStream outputStream;
byte[] buffer = new byte[32];
int bytes;
public SocketThread(Socket sock) {
socket = sock;
InputStream tmpIn = null;
OutputStream tmpOut = null;
try {
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
}
catch (IOException e) {}
inputStream = tmpIn;
outputStream = tmpOut;
EntryActivity.connected = true;
buffer = "connect".getBytes();
EntryActivity.UIupdater.obtainMessage(0, buffer.length, -1, buffer).sendToTarget();
}
public void run() {
try {
while (!Thread.currentThread().isInterrupted()) {
bytes = inputStream.read(buffer);
EntryActivity.UIupdater.obtainMessage(0, bytes, -1, buffer).sendToTarget();
}
} catch (IOException e) {
}
}
}
And here is the handler:
static Handler UIupdater = new Handler() {
public void handleMessage(Message msg) {
int numOfBytes = msg.arg1;
byte[] buffer = (byte[]) msg.obj;
strRecieved = new String(buffer);
strRecieved = strRecieved.substring(0, numOfBytes);
if (strRecieved.equals("connect"))
// Update a TextView
status.setText(R.string.connected);
else
// Do something else;
}
};
I verified that the connection was established (using my Server code), but the TextView was not modified!
Try using handler.sendMessage( handler.obtainMessage(...) ) instead of handler.obtainMessage(...).sendToTarget().
Since obtainMessage() retrieve a Message from the global message pool, it may be that the target is not set properly.
Try using below sample code. I hope it will help you.
byte[] buffer = new byte[32];
static int REFRESH_VIEW = 0;
public void onCreate(Bundle saveInstance)
{
RefreshHandler mRefreshHandler = new RefreshHandler();
final Message msg = new Message();
msg.what = REFRESH_VIEW; // case 0 is calling
final Bundle bData = new Bundle();
buffer = "connect".getBytes();
bData.putByteArray("bytekey", buffer);
msg.setData(bData);
mRefreshHandler.handleMessage(msg); // Handle the msg with key and value pair.
}
/**
* RefreshHandler is handler to refresh the view.
*/
static class RefreshHandler extends Handler
{
#Override
public void handleMessage(final Message msg)
{
switch(msg.what)
{
case REFRESH_VIEW:
final Bundle pos = msg.getData();
final byte[] buffer = pos.getByteArray("bytekey");
String strRecieved = new String(buffer);
//Update the UI Part.
status.setText("Set whatever you want. " + strRecieved);
break;
default:
break;
}
}
};

Categories

Resources