How do combine MqttClient and AsyncTask?

30
July 28, 2019, at 10:20 PM

When using MqttClient in AsnyTask, the client callback to MqttListener.messageArrived() is executed after Async.onPostExecute().

That means that the reply variable will be set after it is passed to the listener callback.

If onTaskCompleted is called from the MqttClient thread (from messageArrived()), an Exception is thrown from inside onTaskCompleted:

MqttException (0) - android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.

public class MqttRequestHandler extends AsyncTask<Object, Void, String> implements MqttCallback {
    private OnTaskCompleted listener;
    String reply = "";
    public MqttRequestHandler(OnTaskCompleted listener) {
        this.listener = listener;
    }
    @Override
    protected String doInBackground(Object... params) {
        try {
            MqttClient client = new MqttClient("tcp://192.168.1.101", "test-client", new MemoryPersistence());
            client.setCallback(this);
            client.connect();
            client.subscribe(setup.topic);
        } catch (Exception e) {
            Log.e("MqttResponseHandler", e.toString());
        }
        return ""; //dummy, since we have to use the callback
    }
    @Override
    public void connectionLost(Throwable cause) {
        Log.d("MqttRequestHandler", "connectionLost: " + cause.toString());
    }
    @Override
    public void messageArrived(String topic, MqttMessage message) {
        this.reply = message.toString(); // not empty
    }
    @Override
    public void deliveryComplete(IMqttDeliveryToken token) {
    }
    protected void onPostExecute(String dummy) {
        listener.onTaskCompleted(this.reply); // empty string!
    }
}

listener.onTaskCompleted(..) hangs when to doing ImageView.setImageBitmap(). The error message is received in connectionLost().

Answer 1

You can't Change a View from another thread, you have to make sure to Access the View from the Thread it was created in, this should be the UI Thread. You can refer to this Post

How do we use runOnUiThread in Android?

Inside your listener.onTaskCompleted(..) function you should make sure to Access your Views from the UI Thread.

If you want to use only the received String you can remove the OnPostexecute and do your onTaskcompleted inside your messagearrived callback.

Remove

protected void onPostExecute(String dummy) {
    listener.onTaskCompleted(this.reply); // empty string!
}

and Change

@Override
public void messageArrived(String topic, MqttMessage message) {
    this.reply = message.toString(); // not empty
}

to

@Override
public void messageArrived(String topic, MqttMessage message) {
    listener.onTaskCompleted(message.toString())
}
READ ALSO
Java: Getting arraylist into RecyclerView item

Java: Getting arraylist into RecyclerView item

I have RecyclerView (mCourseList), that list has items and those items contain some information about different courses (course name, sum of par numbers etc primitive data)I need to get every courses (every items) their all individual set of par numbers...

49
My Samsung A5 apps that can appear on the top can&#39;t seem to appear on the top anymore? [on hold]

My Samsung A5 apps that can appear on the top can't seem to appear on the top anymore? [on hold]

Basically I have this Samsung A5 (2016) which recieved a software update in November 5thSince then the "screen overlay" or "apps that can appear on the top" is not functioning correctly

45
Cannot run job of SimpleJobService

Cannot run job of SimpleJobService

I've a simple job service class where I've implemented onRunJob methodI am expecting it to run for once and then finish

31