问题
I am using Mosquitto Mqtt along with paho API to receive push messages on android device. But as soon as the network connectivity changes it stops receiving messages. Here are the steps to reproduce the issue with simple test case:
1) Create a simple activity.
2) On Activity StartUp connects to mosquitto test server (test.mosquitto.org:1883) through paho API.
3) Subscribe to some topic.
4) Publish some message to the topic.
Result: Mqtt Client receives all the messages published to the topic. Now
5) Disable internet connection on the mobile (mobile data)
6) Publish some message to the topic.
7) Reconnect internet.
Result: Client Does not receive any message published after internet connection was disabled.
As KeepAliveInterval has been kept to high value (30 minutes), it should receive all messages after reconnecting to the internet.
The same use case (same code) is working for simple java project (non-android) where I disable internet on my laptop to run the use case.
Any idea why it is not working on android device??? Am I missing something?
Note:
1) Using mqtt-client-0.4.1
2) Android target API level 11
3) Not putting device to sleep mode during the test.
4) Does not get any call in connectionLost callback and all the 4 threads of mqtt callback are running throughout the test case i.e connection the the mosquitto server is intact.
回答1:
The Java client library is at the mercy of the underlying networking API to a certain extent. When publish is called, it will write an MQTT packet to the socket. If that write fails, then connection lost will be called, if that write works then the client library will carry on. The difference in behaviour you are seeing is because the networking libraries are behaving differently in these circumstances.
The MQTT keepalive interval is meant to help with this. Under certain circumstances a TCP connection may appear to be live when it is not. This is especially possible on mobile or satellite connected devices - you can't expect the networking APIs to work exactly the same in all circumstances. Keepalive sends a ping packet to the server and expects a response - if that response is not received, the session is assumed to be closed.
If you set the keepalive interval to say 10 seconds, then the connection should be recognised as broken within 15 to 20 seconds.
回答2:
You can attach MqttCallback listener to MqttAsyncclient . It has callback method connection lost which will get called when connection lost event occured or paho disconnects.
回答3:
To fix the issue, I had to make an explicit ping to the broker whenever internet connection is back on (along with a timer to wait for ping response). If ping fails or timer goes out, I forcefully terminate the existing connection (disconnectForcibly) and then explicitly call connectionLost method. (Then reconnect from connectionLost method only).
回答4:
In Your Service :-
//Receiver that notifies the Service when the phone gets data connection
private NetworkConnectionIntentReceiver netConnReceiver;
Create the Following Class:-
/*
* Called in response to a change in network connection - after losing a
* connection to the server, this allows us to wait until we have a usable
* data connection again
*/
class NetworkConnectionIntentReceiver extends BroadcastReceiver
{
private static String TAG ="NetworkConnectionIntentReceiver";
@Override
public void onReceive(Context ctx, Intent intent)
{
// we protect against the phone switching off while we're doing this
// by requesting a wake lock - we request the minimum possible wake
// lock - just enough to keep the CPU running until we've finished
PowerManager pm = (PowerManager) ctx.getSystemService(ctx.POWER_SERVICE);
PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "MQTT");
wl.acquire();
Connection c = Connections.getInstance(ctx).getConnection(clientHandle);
final ActionListener callback = new ActionListener(ctx,
ActionListener.Action.CONNECT, clientHandle,null);
c.getClient().setCallback(new MqttCallbackHandler(ctx, clientHandle,messenger_where_incoming_messages_tobe_sent));
c.getClient().connect(c.getConnectionOptions(), null, callback);
/* The Above Reconnect Logic can be put up in a Reconnect() function.
* OR WRITE Any Other LOGIC TO RECONNECT TO MQTT
*/
// we're finished - if the phone is switched off, it's okay for the CPU
// to sleep now
wl.release();
}
Now Call the Following Method Somewhere Appropriate in OnResume() or onCreate to Register the BroadcastReceiver.
synchronized void handleNetworkChange()
{
// changes to the phone's network - such as bouncing between WiFi
// and mobile data networks - can break the MQTT connection
// the MQTT connectionLost can be a bit slow to notice, so we use
// Android's inbuilt notification system to be informed of
// network changes - so we can reconnect immediately, without
// haing to wait for the MQTT timeout
if (netConnReceiver == null)
{
netConnReceiver = new NetworkConnectionIntentReceiver();
registerReceiver(netConnReceiver,
new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
}
}
回答5:
I fixed recconect bug as follows (using rxJava2, but not required):
public void reconnect() {
Completable.create(emitter -> {
while (!mqttClient.isConnected()) {
mqttClient.connect(options, null, new IMqttActionListener() {
@Override
public void onSuccess(IMqttToken asyncActionToken) {
emitter.onComplete();
}
@Override
public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
LogHelper.d(TAG,"try to connect failed");
}
});
Thread.sleep(2000);
}
emitter.onComplete();
})
.subscribeOn(Schedulers.io())
.subscribe();
}
and an example call
private BroadcastReceiver changeNetworkStateReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (Objects.equals(intent.getAction(), NetworkStateReceiver.EVENT_CHANGE_NETWORK_STATE)) {
if(Utils.isOnline(context)) {
mqttClient.reconnect();
}
}
}
};
回答6:
I already had this problem and fix it with check MqttAndroidClient connection and using .isConnected()
in time intervals.
来源:https://stackoverflow.com/questions/25176643/android-paho-mqtt-client-does-not-receive-messages-once-network-connectivity-c