Im trying to use Eclipse Paho MQTT client on my Android app to receive MQTT messages.
Im receiving ~100 message/second, messages are fairly small (basically small json objects). These messages are coming from Mosquitto broker.
When I subscribe to MQTT topic, and start to receive messages, my Android app UI almost freezes. I do not even do anything about the received message on messageArrived callback.
My Eclipse Paho MQTT client usage is super basic, almost the same as in Eclipse Paho example.
Is Eclipse Paho MQTT client bad on performance, or is there something I might be doing wrong?
Im using:
org.eclipse.paho.client.mqttv3:1.1.0 & org.eclipse.paho.android.service:1.1.1
Update
Below my actual code, which is part of the fragment. So in this test im just logging the received message topic. Also with out logging, I got same result, my app almost freezes.
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mqttAndroidClient = new MqttAndroidClient(getActivity().getApplicationContext(), "tcp://xx.xx.xx.xx:1883", MqttClient.generateClientId());
mqttAndroidClient.setCallback(new MqttCallbackExtended() {
#Override
public void connectComplete(boolean b, String s) {
}
#Override
public void connectionLost(Throwable throwable) {
}
#Override
public void messageArrived(String topic, MqttMessage mqttMessage) throws Exception {
Log.d("Mqtt", "messageArrived " + topic);
}
#Override
public void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) {
}
});
}
#Override
public void onStart() {
super.onStart();
MqttConnectOptions mqttConnectOptions = new MqttConnectOptions();
mqttConnectOptions.setAutomaticReconnect(true);
mqttConnectOptions.setCleanSession(true);
try {
mqttAndroidClient.connect(mqttConnectOptions, null, new IMqttActionListener() {
#Override
public void onSuccess(IMqttToken asyncActionToken) {
try {
mqttAndroidClient.subscribe("messages/#", 0);
} catch (Exception exception) {
Log.e("Mqtt", "subscribe error", exception);
}
}
#Override
public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
Log.e("Mqtt", "Connection onFailure ", exception);
}
});
} catch (Exception exception) {
Log.e("Mqtt", "error " + exception);
}
}
The problem is that Paho Android Service is not using own thread to handle connection so everything is done in UI thread.
I ended up using Paho MqttAsyncClient, which handles connection in own tread its own.
Related
I'm playing around with MQTT and Android, but I can't seem to connect the client to the broker. This is how the code looks like:
String clientId = MqttClient.generateClientId();
MqttAndroidClient client = new MqttAndroidClient(this, brokerIp, clientId);
client.setCallback(new MqttCallback() {
#Override
public void connectionLost(Throwable cause) {
Log.i(TAG, "connectionLost");
}
#Override
public void messageArrived(String topic, MqttMessage message) throws Exception {
Log.i(TAG, "messageArrived");
}
#Override
public void deliveryComplete(IMqttDeliveryToken token) {
Log.i(TAG, "deliveryComplete");
}
});
client.connect().setActionCallback(new IMqttActionListener() {
#Override
public void onSuccess(IMqttToken asyncActionToken) {
Log.i(TAG, "Connection success");
}
#Override
public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
Log.i(TAG, "Connection failed: ", exception);
}
});
The problem is that none of the callbacks are ever triggered. Running mosquitto on verbose mode there are no connections coming in from this client, and checking the log I don't see any Exception raised.
I tried locally and on the cloud and it doesn't connect to any, while a client I have on the backend side can connect to both using the same host and port.
What am I missing?
Turns out the MqttService needs to be declared in the manifest to be able to bind to the Paho Android Service correctly:
<service android:name="org.eclipse.paho.android.service.MqttService"/>
I use Quickblox for chat room
My code:
final QBChatDialog dialog = DialogUtils.buildPrivateDialog(id);
dialog.setType(QBDialogType.PRIVATE);
QBRestChatService.createChatDialog(dialog).performAsync(new QBEntityCallback<QBChatDialog>() {
#Override
public void onSuccess(QBChatDialog result, Bundle params) {
try {
QBChatMessage chatMessage = new QBChatMessage();
chatMessage.setBody("Hi there!");
dialog.sendMessage(chatMessage);
} catch (SmackException.NotConnectedException e) {
Log.i("errorCheck", "Chat: NO : " + e.getMessage());
}
}
#Override
public void onError(QBResponseException responseException) {
Log.i("errorCheck", "Chat: FAIL" + responseException.getMessage());
}
});
I get this error :
Client is not, or no longer, connected. error
But I'm sure my client is connected
You need to do the following before sending message:
qbChatDialog.initForChat(QBChatService.getInstance());
I have a PublishProcessor which emits values continuously. And I have subscribed the PublishProcessor with two subscribers which observe on two different thread. While the first subscriber continuously receives the data in onNext(T), the second subscriber throws error Error: Could not emit value due to lack of requests after receiving few calls to onNext(T)
Below is my implementation
PublishProcessor<byte[]> publishProcessor = PublishProcessor.create()
dataFlowable.subscribeOn(Schedulers.newThread()).subscribe(publishProcessor);
Subscriber1
publishProcessor.observeOn(Schedulers.newThread())
.subscribeWith(new DisposableSubscriber<byte[]>() {
#Override public void onNext(byte[] bytes) {
//Log.i("Sub1 ", "Data received");
}
#Override public void onError(Throwable t) {
}
#Override public void onComplete() {
Log.i("Record ", "complete");
}
})
Subscriber2
publishProcessor.observeOn(Schedulers.newThread())
.subscribeWith(new DisposableSubscriber<byte[]>() {
#Override public void onNext(byte[] moreData) {
Log.i("Sub2 ", "Data received");
}
#Override public void onError(Throwable t) {
Log.i("Sub2 ", t.getMessage() + " "); // error received after few call to onNext()
}
#Override public void onComplete() {
Log.i("Sub2 ", "complete");
}
})
This is a MissingBackpressureException. It is occurring because the publisher is producing faster than the subscribers can consume. PublishProcessor does not apply backpressure from its downstream subscribers to its upstream sources.
What is dataFlowable? Why not subscribe to it directly?
Question
Why I am able to connect to my server over my mainActivity , but not over a fragment?
Setup
Program 1 - works...
Right now, I have two programs.
The first one is called mqtt_test which includes a MainActivity, a Button and the connection-class Mqtt. So there are no fragments.
With that program I am able to connect to my Server, subscribe and receive messages.
Code of first programm
public class mqtt {
private Context context;
private String broker = "tcp://10.34.5.134:1883";
private String clientId= "DefaultName";
private MqttAndroidClient client;
private ConnectionListener connectionListener;
private static final String TAG_MQTT= "MQTT";
public mqtt(Context context)
{
this.context = context;
}
public void connect()
{
final String clientId = MqttClient.generateClientId();
//set options
MqttConnectOptions options = new MqttConnectOptions();
options.setMqttVersion(MqttConnectOptions.MQTT_VERSION_3_1);
client =
new MqttAndroidClient(context, broker,
clientId);
try {
IMqttToken token = client.connect(options);
token.setActionCallback(new IMqttActionListener() {
#Override
public void onSuccess(IMqttToken asyncActionToken) {
// We are connected
Log.d(TAG_MQTT, "onSuccess");
connectionListener.connected(true);
client.setCallback(new MqttCallback() {
#Override
public void connectionLost(Throwable cause) {
Log.d(TAG_MQTT, "connectionLost: ");
}
#Override
public void messageArrived(String topic, MqttMessage message) throws Exception {
Log.d(TAG_MQTT, "messageArrived: Message: " + message.toString() + " with topic: " + topic);
}
#Override
public void deliveryComplete(IMqttDeliveryToken token) {
Log.d(TAG_MQTT, "deliveryComplete: ");
}
});
}
#Override
public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
// Something went wrong e.g. connection timeout or firewall problems
Log.d(TAG_MQTT, "onFailure");
connectionListener.connected(false);
}
});
} catch (MqttException e) {
e.printStackTrace();
}
}
public void subscribe(final String topic, int qos)
{
if(client.isConnected())
{
try {
IMqttToken subToken = client.subscribe(topic, qos);
subToken.setActionCallback(new IMqttActionListener() {
#Override
public void onSuccess(IMqttToken asyncActionToken) {
// The message was published
Log.d(TAG_MQTT, "onSuccess: Subscripted with topic: " + topic);
}
#Override
public void onFailure(IMqttToken asyncActionToken,
Throwable exception) {
// The subscription could not be performed, maybe the user was not
// authorized to subscribe on the specified topic e.g. using wildcards
Log.d(TAG_MQTT, "onFailure: The subscription failed");
}
});
} catch (MqttException e) {
e.printStackTrace();
}
}
}
public void publish(String topic, String payload, int qos)
{
byte[] encodedPayload = new byte[0];
try {
encodedPayload = payload.getBytes("UTF-8");
MqttMessage message = new MqttMessage(encodedPayload);
client.publish(topic, message);
Log.d(TAG_MQTT, "publish: Published message:" + payload + " to topic: " + topic);
} catch (UnsupportedEncodingException | MqttException e) {
e.printStackTrace();
Log.d(TAG_MQTT, "publish: Error");
}
}
public void setConnectionListener(ConnectionListener connectionListener) {
this.connectionListener = connectionListener;
}
}
Program 2 - doesn't work
In my second program I am using nearly the same code. However, I am using fragments for future business. In some fragments are buttons, which are calling the right method.
If I press the button, then the right method gets called, like in the first program.
But the program jumps over the async task. OnSucces or onFailure never gets called.
IMqttToken token = client.connect(null, new IMqttActionListener() {
#Override
public void onSuccess(IMqttToken asyncActionToken) {
// connected
Log.d(TAG_CONNECTION, "onSuccess");
connectionListener.connected(true);
client.setCallback(new MqttCallback() {
#Override
public void connectionLost(Throwable cause) {
Log.d(TAG_CONNECTION, "connectionLost: ");
}
#Override
public void messageArrived(String topic, MqttMessage message) throws Exception {
Log.d(TAG_CONNECTION, "messageArrived: Message: " + message.toString() + " with topic: " + topic);
}
#Override
public void deliveryComplete(IMqttDeliveryToken token) {
Log.d(TAG_CONNECTION, "deliveryComplete: ");
}
});
}
#Override
public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
Log.d(TAG_CONNECTION, "onFailure");
connectionListener.connected(false);
Log.d(TAG_CONNECTION, exception.getMessage());
}
});
Then I called the connect-method over a new thread:
#Override
public void doSmth() {
new Thread(new Runnable() {
public void run() {
// a potentially time consuming task
mqttConnection.connect();
}
}).start();
}
Finally I got an answer:
D/CONNECTION: cannot start service org.eclipse.paho.android.service.MqttService
I don't understand why this doesn't work. Maybe you have some input.
To be clear: Both programs do have the same permissions:
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
Assumption
I think, I have to use more asycTasks to solve this problem.
Input/links
It would be awesome, if you could share some links. In the best case with some examples. I only found examples wich are running in a single MainActivity.
The error
D/CONNECTION: cannot start service org.eclipse.paho.android.service.MqttService
possibly indicates that the entry
<service android:name="org.eclipse.paho.android.service.MqttService">
</service>
in AndroidManifest.xml is missing
I am trying to create a simple android app that controls my robot. All the communication is done using mqtt and eclipse paho for android, but I am very new to the protocol. I cannot find a simple explanation of how to get data from a subscribed topic. The best one I found was HiveMQ android tutorial
but that did not explain how to get the data from the callbacks. Any assistance would be appreciated.
For android I have used Paho Android project, very simple to use, here are the steps:
Intialize a client, set required options and connect.
MqttAndroidClient mqttClient = new MqttAndroidClient(BaseApplication.getAppContext(), broker, MQTT_CLIENT_ID);
//Set call back class
mqttClient.setCallback(new MqttCallbackHandler(BaseApplication.getAppContext()));
MqttConnectOptions connOpts = new MqttConnectOptions();
IMqttToken token = mqttClient.connect(connOpts);
Subscribe to a topic.
token.setActionCallback(new IMqttActionListener() {
#Override
public void onSuccess(IMqttToken arg0) {
mqttClient.subscribe("TOPIC_NAME" + userId, 2, null, new IMqttActionListener() {
#Override
public void onSuccess(IMqttToken asyncActionToken) {
Log.d(LOG_TAG, "Successfully subscribed to topic.");
}
#Override
public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
Log.d(LOG_TAG, "Failed to subscribed to topic.");
}
});
}
#Override
public void onFailure(IMqttToken arg0, Throwable arg1) {
Log.d(LOG_TAG, errorMsg);
}
});
Define your callback handler class.
public class MqttCallbackHandler implements MqttCallbackExtended {
#Override
public void connectComplete(boolean b, String s) {
Log.w("mqtt", s);
}
#Override
public void connectionLost(Throwable throwable) {
}
#Override
public void messageArrived(String topic, MqttMessage mqttMessage) throws Exception {
Log.w("Anjing", mqttMessage.toString());
}
#Override
public void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) {
}
}
Also set following in manifest file.
<service android:name="org.eclipse.paho.android.service.MqttService" >
</service>
Would recommend visiting their project on GitHub and going through samples online.
Eclipse Paho Android
Hoping this helps. If you have more questions please visit
Android step by step guide using Eclipse Paho
Cheers !