so in my current workaround i m simply creating a new client every time my alert fires.
//alert firing
starts++
if(client!=null) {
try {
//disconnect if client is connected
client.disconnect().get();
} catch (ExecutionException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
client=null;
//some stuff happening
buildClient()
//do some subs
connectClient()
private void buildClient(){
client = Mqtt3Client.builder()
.identifier(manufacturer+model)
.addConnectedListener(new MqttClientConnectedListener() {
int id=starts;
@Override
public void onConnected(MqttClientConnectedContext context) {
running=true;
Log.v(connectionLogTag, "connectedListener "+ id);
lastConnectedAttempts=0;
if(startUpWakeLock.isHeld()&&id==starts){
startUpWakeLock.release();
Log.v(connectionLogTag, "startUpWakeLock released in connect");
if(!startUpWakeLock.isHeld())
Log.v(connectionLogTag, "startUpWakeLock not held anymore");
}else{
rescheduleAlarm(default_Alarm_Duration);
}
}
}).addDisconnectedListener(new MqttClientDisconnectedListener() {
// id used to identify and make sure only the current client may reconnect
int id=starts;
long maxDelay=4*60;
@Override
public void onDisconnected(MqttClientDisconnectedContext context) {
Log.v("currrThreadName","disconnect: "+Thread.currentThread().getName());
int contextAttempts=context.getReconnector().getAttempts();
String reason="disconnectedListener "+id+" attempt "+contextAttempts+" "+context.getCause().getMessage();
Log.v(connectionLogTag, reason);
// if the id of the listener is = starts it may attempt to reconnect
if(starts==id){
int attempts=lastConnectedAttempts;
lastConnectedAttempts++;
if(context.getCause().getMessage().equals(onMainThreadError)){
if(contextAttempts>0){
attempts=contextAttempts-1;
}
}
if(startUpWakeLock.isHeld() && attempts>1 ){
startUpWakeLock.release();
Log.v(connectionLogTag, "startUpWakeLock released in disconnect");
if(!startUpWakeLock.isHeld())
Log.v(connectionLogTag, "startUpWakeLock not held anymore");
}
long delay=5 * attempts;
if(attempts>6){
delay=maxDelay;
}else{
if(attempts>2)
delay=delay*attempts;
}
Log.v(connectionLogTag, "current attempts "+attempts+" current delay "+delay);
context.getReconnector()
.reconnect(true)
.delay(delay, TimeUnit.SECONDS);
try {
reason=reason+" delay: "+delay;
LogInExternal(DISCONNECT_LOG_FILE,true,reason);
} catch (IOException e) {
e.printStackTrace();
}
}
}
})
.serverHost(serverUni)//"134.60.71.110"
.serverPort(1883)
.buildAsync();
}
public void connectClient(){
Log.v(connectionLogTag, "connecting with username: "+username+" and pw "+password);
client.connectWith().cleanSession(false)
.keepAlive(240)
.send()
.whenComplete((connAck, throwable) -> {
//will throw “MQTT client is already connected or connecting.” error since already scheduled reconnector
if (throwable != null) {
Log.v(connectionLogTag, "connect failure -> release");
Log.v(connectionLogTag, throwable.getMessage());
} else {
Log.v(connectionLogTag, "connect");
}
});
}
This approach has the drawback that when my device is in doze and has no connection every alert will spawn a new disconnectlistener of the new client. These will accumulate and once i have connectivity keep interrupting the currenct client by once reconnecting(since now their timers can run out).
Also i don’t know if all the used resources will be cleaned up at some point.
and the way i would like it to go instead is to keep my client and simply call connect even if there is a reconnect scheduled:
// we wake up our device in doze with an alarm and acquire a wakelock for a short period
if(alertingToTestConnection()){
try {
//asyncClient
client.disconnect()
.whenComplete((connAck, throwable) ->{
// we end up here if we were connected already
// this means the disconnect happend and the disconnectlistener will cause a reconnect
if (throwable != null) {
Log.v(connectionLogTag, "##############testing throwable");
Log.v(connectionLogTag, throwable.getMessage());
} else {
Log.v(connectionLogTag, "############## connected");
}
}).get(500,TimeUnit.MILLISECONDS);
} catch (ExecutionException e) {
connectClient();
Log.v(connectionLogTag, "#############Exec excep");
e.printStackTrace();
} catch (InterruptedException e) {
connectClient();
Log.v(connectionLogTag, "#############Interrupt excep");
e.printStackTrace();
} catch (TimeoutException e) {
// if we end up here we weren't connected but a reconnect will already be scheduled in delay seconds.
// however since we will go back in doze we want this reconnect to happen now
// calling connect() wont work however since we are already trying to connect
connectClient();
Log.v(connectionLogTag, "#############Timeout excep");
e.printStackTrace();
}
return START_STICKY;
}
Is there any way to make this approach work? to let my client that has a reconnect scheduled from its disconnectlistener try to reconnect immediatly?
I saw that all calls to the methods of MqttClientReconnector of a disconnectlistener should only happen in the disconnectlistener onDisconnect(context) method. So i cant just reference it and call reconnect(true) (i tried it failed).