I am stucked and can´t find the way to start again or bind again the bluetooth service in my app. The app has 3 fragments, tabs managed FragmentPagerAdapter. In the first fragment you can discover, pair, and communicate with the BT device. In the second and third tab you must interact with the device, can not get connection neither keep the service connected.

Here it goes the first fragment:

public class Conexiones extends Fragment implements ServiceConnection, SerialListener {
public BluetoothAdapter BTAdapter;
private ListView listView; // detectados
private ArrayList mDeviceList;
public Button conectar, actualizar;
private ArrayAdapter m_DiscoveredPeersAdapter;
BluetoothDevice bdDevice;
BluetoothClass dbClass;
ArrayList listaBTDevices = null;
View view;

public SerialSocket socket;
public SerialService service;

public Conexiones(){

}

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
view = inflater.inflate(R.layout.fragment_conexiones, container, false );
BTAdapter = BluetoothAdapter.getDefaultAdapter();
listView = (ListView) this.view.findViewById(R.id.listView);
mDeviceList = new ArrayList<>();
m_DiscoveredPeersAdapter = new ArrayAdapter(getActivity(), android.R.layout.simple_list_item_1, mDeviceList);
listView.setAdapter(m_DiscoveredPeersAdapter);
listItemClicked = new ListItemClicked();
clicked = new ButtonClicked();

checkBTPermissions();
listaBTDevices = new ArrayList();
m_DiscoveredPeersAdapter.notifyDataSetChanged();
if (BTAdapter == null || !BTAdapter.isEnabled()) {
Intent turnOn = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(turnOn, 1);
}
int MY_PERMISSIONS_REQUEST_ACCESS_COARSE_LOCATION = 1;
ActivityCompat.requestPermissions(activity,
new String[]{Manifest.permission.ACCESS_COARSE_LOCATION},
MY_PERMISSIONS_REQUEST_ACCESS_COARSE_LOCATION);

if (BTAdapter.isEnabled()){
BTAdapter.startDiscovery();
Log.e(“mio”, “dp de star discovery”);
}
else{
Intent turnOn = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(turnOn, 1);
Log.e(“mio”, “no weisa”);
}

IntentFilter filter = new IntentFilter();
filter.addAction(BluetoothDevice.ACTION_FOUND);
filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED);
filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
activity.registerReceiver(mReceiver, filter);

return view;
}

@Override
public void onStart() {
Log.e(“mio”, “dentro de on start “);
dataInicialRecibida=false;
super.onStart();
//getPairedDevices();
this.conectar.setOnClickListener(clicked);
this.actualizar.setOnClickListener(clicked);
listView.setOnItemClickListener(listItemClicked);
MainActivity activity = (MainActivity) getActivity();
texto.setText(“sistema listo”);

}

private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
Log.i(“BT”, “recibe”);
if (BluetoothAdapter.ACTION_DISCOVERY_STARTED.equals(action)) {
//discovery starts, we can show progress dialog or perform other tasks
Log.i(“BT”, “empezamos BT”);
}
if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) {
//discovery starts, we can show progress dialog or perform other tasks
Log.i(“BT”, “terminiamos BT”);
try {
Method getUuidsMethod = BluetoothAdapter.class.getDeclaredMethod(“getUuids”, null);
ParcelUuid[] uuids = (ParcelUuid[]) getUuidsMethod.invoke(BTAdapter, null);

if(uuids != null) {
for (ParcelUuid uuid : uuids) {
Log.d(TAG, “UUID: ” + uuid.getUuid().toString());
miu=uuid.getUuid().toString();
}
}else{
Log.d(TAG, “Uuids not found, be sure to enable Bluetooth!”);
}

}catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}

}
if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(action)) {
//discovery starts, we can show progress dialog or perform other tasks
Log.i(“BT”, “state changed BT”);
}
if (BluetoothDevice.ACTION_FOUND.equals(action)) {
BluetoothDevice device = intent
.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
// mDeviceList.add(device.getName() + “\n” + device.getAddress());
// DeviceItem newDevice = new DeviceItem(device.getName(), device.getAddress(), “false”);
Log.i(“BTN”, device.getName() + “\n” + device.getAddress());
// mDeviceList.notifyDataSetChanged();
if(listaBTDevices.size()<1) // this checks if the size of bluetooth device is 0,then add the { Log.i("mio", "lista devices menor a 1");// device to the arraylist. m_DiscoveredPeersAdapter.add(device.getName()+"\n"+device.getAddress()); listaBTDevices.add(device); m_DiscoveredPeersAdapter.notifyDataSetChanged(); } else { Log.i("mio", "lista devices maor o igual a 1"); boolean flag = true; // flag to indicate that particular device is already in the arlist or not for(int i = 0; i(context,
android.R.layout.simple_list_item_1, mDeviceList));
}

};

@RequiresApi(api = Build.VERSION_CODES.M)
private void checkBTPermissions() {
if(Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP){
int permissionCheck =getActivity().checkSelfPermission(“Manifest.permission.ACCESS_FINE_LOCATION”);
permissionCheck += getActivity().checkSelfPermission(“Manifest.permission.ACCESS_COARSE_LOCATION”);
if (permissionCheck != 0) {

this.requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION}, 1001); //Any number
}
}else{
Log.d(TAG, “checkBTPermissions: No need to check permissions. SDK version < LOLLIPOP."); } } @Override public void onDestroy() { MainActivity activity = (MainActivity) getActivity(); activity.unregisterReceiver(mReceiver); super.onDestroy(); Log.e("mio", "on destroy "); } @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if(resultCode == RESULT_OK){ Log.d(TAG, "caso okookok."); BTAdapter.startDiscovery(); }else{ Log.d(TAG, "cas no ok."); } } @Override public void onStop() { super.onStop(); Log.e("mio", "on stop"); MainActivity activity = (MainActivity) getActivity(); activity.unregisterReceiver(mReceiver); } @Override public void onServiceConnected(ComponentName name, IBinder binder) { service = ((SerialService.SerialBinder) binder).getService(); Log.e("mio", "on service conectado conexiones "); if(initialStart && isResumed()) { initialStart = false; getActivity().runOnUiThread(this::connect); } } @Override public void onServiceDisconnected(ComponentName name) { service = null; texto.setText("desconectado BT"); Log.e("mio", "desconectado BT conexiones"); } @Override public void onSerialConnect() { texto.setText("conexion BT"); Log.e("mio", "conectado BT conexiones"); } @Override public void onSerialConnectError(Exception e) { texto.setText("error conexion BT"); Log.e("mio", "onSerialConnectError"); } @Override public void onSerialRead(byte[] data) { receive(data); texto.setText("leyendo BT"); Log.e("mio", "leyendo BT "); } private void receive(byte[] data) { receiveText+=new String(data); receiveText=""; } @Override public void onSerialIoError(Exception e) { texto.setText("error conexion BT"); } class ButtonClicked implements View.OnClickListener { @Override public void onClick(View view) { switch (view.getId()) { case R.id.button: listaBTDevices.clear(); m_DiscoveredPeersAdapter.clear(); startSearching(); texto.setText("buscando dispositivos BT"); break; case R.id.button3: break; } } } class ListItemClicked implements AdapterView.OnItemClickListener { @Override public void onItemClick(AdapterView parent, View view, int position, long id) {

bdDevice = listaBTDevices.get(position);
//bdClass = arrayListBluetoothDevices.get(position);
Log.i(“Log”, “The dvice : “+bdDevice.toString());

connect();

}
}

private boolean isNetworkAvailable() {
ConnectivityManager connectivityManager = (ConnectivityManager) service.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();
return activeNetworkInfo != null && activeNetworkInfo.isConnected();
}

private void getPairedDevices() {
// Set pairedDevice = BTAdapter.getBondedDevices();
// if(pairedDevice.size()>0)
{
// for(BluetoothDevice device : pairedDevice)
{
// arrayListpaired.add(device.getName()+”\n”+device.getAddress());
// arrayListPairedBluetoothDevices.add(device);
}
}
// adapter.notifyDataSetChanged();
}

public void send(String str) {
try {
SpannableStringBuilder spn = new SpannableStringBuilder(str+’\n’);
byte[] data = (str).getBytes();
socket.write(data);
} catch (Exception e) {
onSerialIoError(e);
}
}

@SuppressWarnings(“deprecation”)
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
// getActivity().bindService(new Intent(getActivity(), SerialService.class), this, Context.BIND_AUTO_CREATE);
}

private void connect() {

try {

BTAdapter = BluetoothAdapter.getDefaultAdapter();
BluetoothDevice device = BTAdapter .getRemoteDevice(bdDevice.getAddress());
String deviceName = device.getName() != null ? device.getName() : device.getAddress();
socket = new SerialSocket();
service.connect(this, “Connected to ” + deviceName);
socket.connect(getContext(), service, device);
MainActivity activity = (MainActivity) getActivity();
activity.setidEquipo(bdDevice.getAddress());
// conexión ok, cambiar color letras boton

} catch (Exception e) {
//onSerialConnectError(e);
Log.i(“mio”, “error del connect “+e);
// sino hay conexión mantener boton con letras naranjas

}

}

private void startSearching() {
Log.i(“Log”, “in the start searching method”);
MainActivity activity = (MainActivity) getActivity();
IntentFilter intentFilter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
activity.registerReceiver(mReceiver, intentFilter);
BTAdapter.startDiscovery();
}
private void onBluetooth() {
if(!BTAdapter.isEnabled())
{
BTAdapter.enable();
Log.i(“Log”, “Bluetooth is Enabled”);
}
}
private void offBluetooth() {
if(BTAdapter.isEnabled())
{
BTAdapter.disable();
}
}

}

The serial service:

public class SerialService extends Service implements SerialListener {

class SerialBinder extends Binder {
SerialService getService() { return SerialService.this; }
}

private enum QueueType {Connect, ConnectError, Read, IoError}

private class QueueItem {
QueueType type;
byte[] data;
Exception e;

QueueItem(QueueType type, byte[] data, Exception e) { this.type=type; this.data=data; this.e=e; }
}

private final Handler mainLooper;
private final IBinder binder;
private final Queue queue1, queue2;

private SerialListener listener;
private boolean connected;
private String notificationMsg;

public SerialService() {
mainLooper = new Handler(Looper.getMainLooper());
binder = new SerialBinder();
queue1 = new LinkedList<>();
queue2 = new LinkedList<>();
}

@Nullable
@Override
public IBinder onBind(Intent intent) {
return binder;
}

public void connect(SerialListener listener, String notificationMsg) {
this.listener = listener;
connected = true;
this.notificationMsg = notificationMsg;
}

public void disconnect() {
listener = null;
connected = false;
notificationMsg = null;
}

public void attach(SerialListener listener) {
if(Looper.getMainLooper().getThread() != Thread.currentThread())
throw new IllegalArgumentException(“not in main thread”);
cancelNotification();
// use synchronized() to prevent new items in queue2
// new items will not be added to queue1 because mainLooper.post and attach() run in main thread
if(connected) {
synchronized (this) {
this.listener = listener;
}
}
for(QueueItem item : queue1) {
switch(item.type) {
case Connect: listener.onSerialConnect (); break;
case ConnectError: listener.onSerialConnectError (item.e); break;
case Read: listener.onSerialRead (item.data); break;
case IoError: listener.onSerialIoError (item.e); break;
}
}
for(QueueItem item : queue2) {
switch(item.type) {
case Connect: listener.onSerialConnect (); break;
case ConnectError: listener.onSerialConnectError (item.e); break;
case Read: listener.onSerialRead (item.data); break;
case IoError: listener.onSerialIoError (item.e); break;
}
}
queue1.clear();
queue2.clear();
}

public void detach() {
if(connected)
createNotification();
// items already in event queue (posted before detach() to mainLooper) will end up in queue1
// items occurring later, will be moved directly to queue2
// detach() and mainLooper.post run in the main thread, so all items are caught
listener = null;
}

public void onSerialConnect() {
Log.i(“mio”, “dentro on serial connect “);
if(connected) {
Log.i(“mio”, “dentro de connected “);
synchronized (this) {
if (listener != null) {
mainLooper.post(() -> {
if (listener != null) {
listener.onSerialConnect();
} else {
queue1.add(new QueueItem(QueueType.Connect, null, null));
}
});
} else {
queue2.add(new QueueItem(QueueType.Connect, null, null));
}
}
}
}

public void onSerialConnectError(Exception e) {
if(connected) {
synchronized (this) {
if (listener != null) {
mainLooper.post(() -> {
if (listener != null) {
listener.onSerialConnectError(e);
} else {
queue1.add(new QueueItem(QueueType.ConnectError, null, e));
cancelNotification();
disconnect();
}
});
} else {
queue2.add(new QueueItem(QueueType.ConnectError, null, e));
cancelNotification();
disconnect();
}
}
}
}

public void onSerialRead(byte[] data) {
if(connected) {
synchronized (this) {
if (listener != null) {
mainLooper.post(() -> {
if (listener != null) {
listener.onSerialRead(data);
} else {
queue1.add(new QueueItem(QueueType.Read, data, null));
}
});
} else {
queue2.add(new QueueItem(QueueType.Read, data, null));
}
}
}
}

public void onSerialIoError(Exception e) {
if(connected) {
synchronized (this) {
if (listener != null) {
mainLooper.post(() -> {
if (listener != null) {
listener.onSerialIoError(e);
} else {
queue1.add(new QueueItem(QueueType.IoError, null, e));
cancelNotification();
disconnect();
}
});
} else {
queue2.add(new QueueItem(QueueType.IoError, null, e));
cancelNotification();
disconnect();
}
}
}
}

}

The serial socket class:

class SerialSocket implements Runnable {

private static final UUID BLUETOOTH_SPP = UUID.fromString(“00001101-0000-1000-8000-00805F9B34FB”);

private final BroadcastReceiver disconnectBroadcastReceiver;

private Context context;
private SerialListener listener;
private BluetoothDevice device;
private BluetoothSocket socket;
private boolean connected;

SerialSocket() {
disconnectBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if(listener != null)
listener.onSerialIoError(new IOException(“background disconnect”));
disconnect(); // disconnect now, else would be queued until UI re-attached
}
};
}

/**
* connect-success and most connect-errors are returned asynchronously to listener
*/
void connect(Context context, SerialListener listener, BluetoothDevice device) throws IOException {
if(connected || socket != null)
throw new IOException(“already connected”);
this.context = context;
this.listener = listener;
this.device = device;
context.registerReceiver(disconnectBroadcastReceiver, new IntentFilter(Constants.INTENT_ACTION_DISCONNECT));
Executors.newSingleThreadExecutor().submit(this);
}

void disconnect() {
listener = null; // ignore remaining data and errors
// connected = false; // run loop will reset connected
if(socket != null) {
try {
socket.close();
} catch (Exception ignored) {
}
socket = null;
}
try {
context.unregisterReceiver(disconnectBroadcastReceiver);
} catch (Exception ignored) {
}
}

void write(byte[] data) throws IOException {
if (!connected)
throw new IOException(“not connected”);
socket.getOutputStream().write(data);
}

@Override
public void run() { // connect & read
try {
socket = device.createRfcommSocketToServiceRecord(BLUETOOTH_SPP);
socket.connect();
if(listener != null)
listener.onSerialConnect();
} catch (Exception e) {
if(listener != null)
listener.onSerialConnectError(e);
try {
socket.close();
} catch (Exception ignored) {
}
socket = null;
return;
}
connected = true;
try {
byte[] buffer = new byte[1024];
int len;
//noinspection InfiniteLoopStatement
while (true) {
len = socket.getInputStream().read(buffer);
byte[] data = Arrays.copyOf(buffer, len);
if(listener != null)
listener.onSerialRead(data);
}
} catch (Exception e) {
connected = false;
if (listener != null)
listener.onSerialIoError(e);
try {
socket.close();
} catch (Exception ignored) {
}
socket = null;
}
}

}

And the second fragment whereas I need to keep connection or connect to the same device already connected in fragment (“conexiones”):

public class Identificacion extends Fragment implements ServiceConnection, SerialListener {

private String deviceAddress;
private String newline = “\r\n”;
private String receiveText;
private enum Connected { False, Pending, True }
private String sendText;
private SerialSocket socket;
private SerialService service;
private boolean initialStart = true;
private Connected connected = Connected.False;

// constructor requerido vacio
public Identificacion(){

}
@Override
public void onCreate(Bundle savedInstanceState) {
Log.e(“mio”, “dentro on creata identificacion”);
super.onCreate(savedInstanceState);
setRetainInstance(true);
// deviceAddress = getArguments().getString(“device”);
}

@SuppressWarnings(“deprecation”) // onAttach(context) was added with API 23. onAttach(activity) works for all API versions
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
getActivity().bindService(new Intent(getActivity(), SerialService.class), this, Context.BIND_AUTO_CREATE);
}

@Override
public void onDetach() {
try { getActivity().unbindService(this); } catch(Exception ignored) {}
super.onDetach();
}

@Override
public void onResume() {
super.onResume();
/* if(initialStart && service !=null) {
initialStart = false;
getActivity().runOnUiThread(this::connect);
} */
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
view = inflater.inflate(R.layout.fragment_identificacion, container, false );

return view;
}

private void addListenerOnButton() {

bt12.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
EditText txtView = (EditText) aux1;
EditText txtView2 = (EditText) aux2;
TextView txtView3 = (TextView) aux3;
if (pin2 != null && pin2.length() == largo && pin4 != null && pin4.length() == largo){
//consultar BD si exta bien la pass, caso si:
Log.e(“mio”, “dentro de pin y pass con formato ” + pin2);
pin=pin2;
String aenvio=(String)pin2+”;”+pin4;
// enviar pin por BT
connect();
send(aenvio);

}

}

});

}// fin add listener button

private void connect() {
try {
MainActivity activity = (MainActivity) getActivity();
String par3= activity.getidEquipo();
deviceAddress=par3;
Log.e(“mio”, “connect identif valor deviceAddress “+deviceAddress);
//deviceAddress = getArguments().getString(“device”);
BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
BluetoothDevice device = bluetoothAdapter.getRemoteDevice(deviceAddress);
String deviceName = device.getName() != null ? device.getName() : device.getAddress();
// status(“connecting…”);
Log.e(“mio”, “connect identif deviceName “+deviceName);
connected = Connected.Pending;
onAttach(activity);
// socket =
//socket = new SerialSocket();
getActivity().bindService(new Intent(getActivity(), SerialService.class ), this, Context.BIND_ADJUST_WITH_ACTIVITY );
service.connect(this, “Connected to ” + deviceName);
socket.connect(getContext(), service, device);
connected = Connected.True;
Log.e(“mio”, “connect identif salida “+deviceName);
} catch (Exception e) {
onSerialConnectError(e);
}
}

private void send(String str) {
if(connected != Connected.True) {
Toast.makeText(getActivity(), “not connected”, Toast.LENGTH_SHORT).show();
Log.e(“mio”, “dentro send no conectado “+str);
// return;
}
try {
connect();
// SpannableStringBuilder spn = new SpannableStringBuilder(str+’\n’);
Log.e(“mio”, “send conectado “+str);
// spn.setSpan(new ForegroundColorSpan(getResources().getColor(R.color.colorSendText)), 0, spn.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
Toast.makeText(getActivity(), “enviando login a esp”, Toast.LENGTH_SHORT).show();
sendText=str; // poner aca el string de user;pass a enviar al esp32 app
byte[] data = (str + newline).getBytes();
socket.write(data);
} catch (Exception e) {
onSerialIoError(e);
}
}

private void receive(byte[] data) {

receiveText+=(new String(data));
}

@Override
public void onServiceConnected(ComponentName name, IBinder binder) {
service = ((SerialService.SerialBinder) binder).getService();
if(initialStart && isResumed()) {
initialStart = false;
getActivity().runOnUiThread(this::connect);
}
}

@Override
public void onServiceDisconnected(ComponentName name) {
service = null;
}

@Override
public void onSerialRead(byte[] data) {
Log.e(“mio”, “serial leer data “);
receive(data);
}

@Override
public void onSerialIoError(Exception e) {
Log.e(“mio”, “serial io error, desconectar “);
disconnect();
}
}