I am working on a project that can send and receive Strings to and from an Arduino to control and monitor various sensors and lights. I am running into an issue where once I leave the activity that connects to Bluetooth and then return to that same activity after visiting the home activity I am no longer able to send and receive data. The sending and receiving of strings works perfectly until I leave the activity to go to the home activity and come back.
Here is the Java code for the sensor activity:
package com.example.arduinocontrol;
import androidx.appcompat.app.AppCompatActivity;
import androidx.cardview.widget.CardView;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Set;
import java.util.UUID;
import android.annotation.SuppressLint;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.text.method.ScrollingMovementMethod;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
public class uvlight extends AppCompatActivity implements OnClickListener{
private static final int REQUEST_ENABLE_BT = 1;
private CardView uvLight;
//listeners for button presses
Button on, off,clear;
//textbox below buttons
TextView t1,t2,t3;
BluetoothAdapter mBluetoothAdapter;
BluetoothDevice mDevice;
ByteArrayInputStream mSocket;
ConnectedThread mConnectedThread = null;
ConnectThread mConnectThread = null;
@Override
protected void onCreate(Bundle savedInstanceState)
{
//Instantiation
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_uvlight);
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (mBluetoothAdapter == null) {
Toast.makeText(getApplicationContext(),"BT not supported!", Toast.LENGTH_SHORT).show();
return;
}
if (!mBluetoothAdapter.isEnabled()) {
//opens a window to ask user to turn on bluetooth
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, 1);
}
Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices();
if (pairedDevices.size() > 0) {
for (BluetoothDevice device : pairedDevices) {
mDevice = device;
}
}
mConnectThread = new ConnectThread(mDevice);
mConnectThread.start();
try {
setw();
} catch (Exception e) {
e.printStackTrace();
}
}
@SuppressLint("ClickableViewAccessibility")
private void setw() throws IOException {
//text for bluetooth device details
t1=(TextView)findViewById(R.id.textView3);
t2=(TextView)findViewById(R.id.response);
t2.setMovementMethod(new ScrollingMovementMethod());
String name = mDevice.getName().toString();
try {
t1.setText("Connected to: " + name);
} catch (Exception e) {
e.printStackTrace();
}
//links on and off to their element IDs
on=(Button)findViewById(R.id.uvlighton);
off=(Button)findViewById(R.id.uvlightoff);
clear=(Button)findViewById(R.id.clear);
//clears log text
clear.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
t2.setText("");
}
});
on.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v)
{
//sends 'o' char to Arduino
// method to turn on uv light
if(mConnectedThread != null) {
//String sig = "o";
//mConnectedThread.write(sig.getBytes());
int sig = 112;
mConnectedThread.write(sig);
}
}
});
off.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v)
{
//method to turn off uv light
if(mConnectedThread != null) {
//String sig1 = "f";
//mConnectedThread.write(sig1.getBytes());
int sig = 113;
mConnectedThread.write(sig);
}
}
});
}
private class ConnectThread extends Thread {
private final BluetoothSocket mmSocket;
private final BluetoothDevice mmDevice;
//HC-05 unique uuid
private final UUID MY_UUID = UUID.fromString("00001101-0000-1000-8000-00805f9b34fb");
public ConnectThread(BluetoothDevice device) {
BluetoothSocket tmp = null;
mmDevice = device;
Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices();
try {
//creates RFCOMM socket
tmp = device.createRfcommSocketToServiceRecord(MY_UUID);
//shows user they are connected
Toast.makeText(getApplicationContext(), "Connected to your Arduino", Toast.LENGTH_SHORT).show();
//displays bt info in text field
} catch (IOException e) {
Toast.makeText(getApplicationContext(), "Unable to connect!", Toast.LENGTH_SHORT).show();
}
mmSocket = tmp;
}
public void run() {
mBluetoothAdapter.cancelDiscovery();
//need the if for this edge case
try {
mmSocket.connect();
} catch (IOException connectException) {
try {
if (mSocket != null) {
mSocket.close();
}
} catch (IOException closeException) {
Toast.makeText(getApplicationContext(), "Unable to connect socket!", Toast.LENGTH_SHORT).show();
}
return;
}
//new connected thread obj
mConnectedThread = new ConnectedThread(mmSocket);
mConnectedThread.start();
}
public void cancel() {
try {
mmSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//Thread for bluetooth process
private class ConnectedThread extends Thread {
//copies bt socket for threading
private final BluetoothSocket mmSocket;
//copies input stream obj for threading
private final InputStream mmInStream;
//copies output stream obj for threading
private final OutputStream mmOutStream;
public ConnectedThread(BluetoothSocket socket) {
mmSocket = socket;
InputStream tmpIn = null;
OutputStream tmpOut = null;
try {
tmpIn = socket.getInputStream();
} catch (IOException e) {
e.printStackTrace();
}
try {
tmpOut = socket.getOutputStream();
} catch (IOException e) {
e.printStackTrace();
}
mmInStream = tmpIn;
mmOutStream = tmpOut;
}
//reads from Arduino
@Override
public void run() {
byte[] buffer = new byte[1024];
int begin = 0;
int bytes = 0;
while (true) {
try {
bytes += mmInStream.read(buffer, bytes, buffer.length - bytes);
for (int i = begin; i < bytes; i++) {
//end char for a given message from Arduino
if (buffer[i] == "#".getBytes()[0]) {
mHandler.obtainMessage(1, begin, i, buffer).sendToTarget();
begin = i + 1;
if (i == bytes - 1) {
bytes = 0;
begin = 0;
}
}
}
} catch (IOException e) {
break;
}
}
}
//writes to the output stream (in this case the Arduino)
public void write(/*byte[] bytes*/int num) {
try {
Toast.makeText(getApplicationContext(), "sending bytes", Toast.LENGTH_SHORT).show();
mmOutStream.write(num);
} catch (IOException e) {
e.printStackTrace();
}
}
public void cancel() {
try {
mmSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
@Override
public void onClick(View v)
{
try
{
}
catch (Exception e)
{
//displays toast message
Toast.makeText(getApplicationContext(),e.getMessage(), Toast.LENGTH_SHORT).show();
}
}
//Suppresses an annoying handler lear warning
@SuppressLint("HandlerLeak")
Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
byte[] writeBuf = (byte[]) msg.obj;
int begin = (int)msg.arg1;
int end = (int)msg.arg2;
switch(msg.what) {
case 1:
String writeMessage = new String(writeBuf);
writeMessage = writeMessage.substring(begin, end);
//sends message to homepage to turn cardview red
//string called error contains value of writeMessage
Intent intent = new Intent("errorCode").putExtra("error", writeMessage);
LocalBroadcastManager.getInstance(uvlight.this).sendBroadcast(intent);
//write message to the scrolling textbox
t2.append(writeMessage);
break;
}
}
};
}
Here is the Java code for the home activity:
package com.example.arduinocontrol;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import androidx.cardview.widget.CardView;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
public class HomeActivity extends AppCompatActivity implements View.OnClickListener {
private CardView airPump, flowMeter, humiditySensor, levelSwitch1, levelSwitch2, lightStrip, phMeter, uvLight, waterPump, solenoidValve, nutrientPump;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
//defines cards
airPump = (CardView) findViewById(R.id.airpump);
flowMeter = (CardView) findViewById(R.id.flowmeter);
humiditySensor = (CardView) findViewById(R.id.humiditysensor);
levelSwitch1 = (CardView) findViewById(R.id.levelswitch1);
levelSwitch2 = (CardView) findViewById(R.id.levelswitch2);
lightStrip = (CardView) findViewById(R.id.lightstrip);
phMeter = (CardView) findViewById(R.id.phmeter);
uvLight = (CardView) findViewById(R.id.uvlight);
waterPump = (CardView) findViewById(R.id.waterpump);
solenoidValve = (CardView) findViewById(R.id.solenoidvalve);
nutrientPump = (CardView) findViewById(R.id.nutrientpump);
//click listeners
airPump.setOnClickListener(this);
flowMeter.setOnClickListener(this);
humiditySensor.setOnClickListener(this);
levelSwitch1.setOnClickListener(this);
levelSwitch2.setOnClickListener(this);
lightStrip.setOnClickListener(this);
phMeter.setOnClickListener(this);
uvLight.setOnClickListener(this);
waterPump.setOnClickListener(this);
solenoidValve.setOnClickListener(this);
nutrientPump.setOnClickListener(this);
LocalBroadcastManager.getInstance(this).registerReceiver(mReceiver, new IntentFilter("errorCode"));
}
//turns Uvlight card red when an error is sent
private BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String errorMsg = intent.getStringExtra("error");
if (errorMsg.equals("-3")){
uvLight.setCardBackgroundColor(0xFFFF0000);
}
}
};
@Override
public void onBackPressed() {
moveTaskToBack(true);
}
@Override
public void onClick(View v) {
Intent i;
//on click opens the new activity
switch(v.getId()){
case R.id.airpump : i = new Intent(this,Airpump.class); startActivity(i); break;
case R.id.flowmeter : i = new Intent(this,Flowmeter.class); startActivity(i); break;
case R.id.humiditysensor : i =new Intent(this,Humiditysensor.class); startActivity(i); break;
case R.id.levelswitch1 : i = new Intent(this,Levelswitch1.class); startActivity(i); break;
case R.id.levelswitch2 : i = new Intent(this,Levelswitch2.class); startActivity(i); break;
case R.id.lightstrip : i = new Intent(this,Lightstrip.class); startActivity(i); break;
case R.id.phmeter : i = new Intent(this,Phmeter.class); startActivity(i); break;
case R.id.uvlight : i = new Intent(this,uvlight.class); startActivity(i); break;
case R.id.waterpump : i = new Intent(this,Waterpump.class); startActivity(i); break;
case R.id.solenoidvalve : i = new Intent(this,solenoidvalve.class); startActivity(i); break;
case R.id.nutrientpump : i = new Intent(this,Nutrientpump.class); startActivity(i); break;
default:break;
}
}
}
I am new to Android Studio and this is the first time I have had to make a multi-threaded application. Thank You.
you can try to extract the Bluetooth connection method into a simple profit class, similar to "local broadcast manager". When "uvlight" on destroy Bluetooth connection will continue to open. Or you can refer to GitHub's excellent open source libraries, such as: https://github.com/akexorcist/BluetoothSPPLibrary 。 I believe you can learn more in it
User contributions licensed under CC BY-SA 3.0