Keep MQTT Topics Subscribed onResume Activity

旧城冷巷雨未停 提交于 2019-12-24 08:11:51

问题


I've a MQTT Service Class, MyMqttService.class, runing when I log in in my app:

    Intent intent = new Intent(getApplicationContext(), MyMqttService.class);
    startService(intent);

Then I have various Activities and in one of them, I have switch buttons to select which channels I want to subscribe. In my onPause/onResume, I check which buttons are on and which are off and make them go to that same state when I come back to that Activity. The problem is, if there is at least one button on when I resume the Activity, I get an error and my aplication crashes, since my app tries to subscribe, and cant.

My service Class:

public class MyMqttService extends Service implements MqttCallback, IMqttActionListener {

    private final IBinder binder = new MyBinder();

    private MqttAndroidClient mqttClient;
    private MqttConnectOptions mqttConnectOptions;
    private static final MemoryPersistence persistence = new MemoryPersistence();
    private ArrayList<MqttAndroidClient> lostConnectionClients;

    private String clientId = "";
    private boolean isReady = false;
    private boolean doConnectTask = true;
    private boolean isConnectInvoked = false;

    private Handler handler = new Handler();
    private final int RECONNECT_INTERVAL = 10000; // 10 seconds
    private final int DISCONNECT_INTERVAL = 20000; // 20 seconds
    private final int CONNECTION_TIMEOUT = 60;
    private final int KEEP_ALIVE_INTERVAL = 200;

    private String broker_url = "xxx.xxx.xxx.xxx";

    public class MyBinder extends Binder {

        public MyMqttService getService() {

            return MyMqttService.this;
        }
    }

    @Override
    public void onCreate() {
        super.onCreate();
        initMqttClient();
    }

    private void initMqttClient() {
        if(mqttClient != null) {
            mqttClient = null;
        }
        lostConnectionClients = new ArrayList<>();

        mqttConnectOptions = new MqttConnectOptions();
        mqttConnectOptions.setCleanSession(true);
        mqttConnectOptions.setConnectionTimeout(CONNECTION_TIMEOUT);
        mqttConnectOptions.setKeepAliveInterval(KEEP_ALIVE_INTERVAL);

        setNewMqttClient();

        handler.post(connect);
        handler.postDelayed(disconnect, DISCONNECT_INTERVAL);
    }

    private void setNewMqttClient() {
        mqttClient = new MqttAndroidClient(MyMqttService.this, broker_url, clientId, persistence);
        mqttClient.setCallback(this);
    }

    public Runnable connect = new Runnable() {
        public void run() {
            connectClient();
            handler.postDelayed(connect, RECONNECT_INTERVAL);
        }
    };

    public Runnable disconnect = new Runnable() {
        public void run() {
            disconnectClients();
            handler.postDelayed(disconnect, DISCONNECT_INTERVAL);
        }
    };

    private void connectClient() {
        if(doConnectTask) {
            doConnectTask = false;
            try {
                isConnectInvoked = true;
                mqttClient.connect(mqttConnectOptions, null, this);
            } catch (MqttException ex) {
                doConnectTask = true;
                System.out.println("MQTT exception 1: " + ex.toString());
            }
        }
    }

    private void disconnectClients() {
        if (lostConnectionClients.size() > 0) {
            // Disconnect lost connection clients
            for (MqttAndroidClient client : lostConnectionClients) {
                if (client.isConnected()) {
                    try {
                        client.disconnect();
                    } catch (MqttException e) {
                        System.out.println("MQTT exception 2: " + e.toString() );
                    }
                }
            }

            // Close already disconnected clients
            for (int i = lostConnectionClients.size() - 1; i >= 0; i--) {
                try {
                    if (!lostConnectionClients.get(i).isConnected()) {
                        MqttAndroidClient client = lostConnectionClients.get(i);
                        client.close();
                        lostConnectionClients.remove(i);
                    }
                } catch (IndexOutOfBoundsException e) {
                    System.out.println("MQTT exception 3: " + e.toString());
                }
            }
        }
    }

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

    @Override
    public void onSuccess(IMqttToken asyncActionToken) {
        isReady = true;

        // subscribe here
        subscribe("");
    }

    @Override
    public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
        setNewMqttClient();
        isReady = false;
        doConnectTask = true;
        isConnectInvoked = false;
    }

    public void subscribe(String topic) {
        try {
            mqttClient.subscribe(topic, 0);
            isReady = true;
        } catch (MqttSecurityException mqttSexEx) {
            isReady = false;
        } catch (MqttException mqttEx) {
            isReady = false;
        }
    }

    private void unsubscribe(String topic) {
        try {
            mqttClient.unsubscribe(topic);
        } catch (MqttSecurityException mqttSecEx) {
            System.out.println("MQTT exception 4: " + mqttSecEx.toString());
        } catch (MqttException mqttEx) {
            System.out.println("MQTT exception 5: " + mqttEx.toString());
        }
    }

    private void publish(String topic, String jsonPayload) {
        if(!isReady) {
            return;
        }

        try {
            MqttMessage msg = new MqttMessage();
            msg.setQos(0);
            msg.setPayload(jsonPayload.getBytes("UTF-8"));
            mqttClient.publish(topic, msg);
        } catch (Exception ex) {
            System.out.println("MQTT exception 6: " + ex.toString());
        }
    }



    @Override
    public void connectionLost(Throwable cause) {
        System.out.println("MQTT exception 7: " + cause.getMessage());
    }

    @Override
    public void messageArrived(String topic, MqttMessage message) throws Exception {
        String payload = new String(message.getPayload());
        // do something
    }

    @Override
    public void deliveryComplete(IMqttDeliveryToken token) {
        System.out.println("MQTT exception 8: deliveryComplete()");
    }
}

My activity with the swich buttons, where I subscribe:

public class DefinicoesActivity extends AppCompatActivity {

    private Switch switchSaude;
    private Switch switchAlimentacao;
    private Switch switchDesporto;

    private static Bundle bundle = new Bundle();

    private String topico;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_definicoes);

        final MqttAndroidClient mqttAndroidClient = new MqttAndroidClient(this.getApplicationContext(), "tcp://5.196.27.244:1883", "users");

        mqttAndroidClient.setCallback(new MqttCallback() {
            @Override
            public void connectionLost(Throwable cause) {

            }

            @Override
            public void messageArrived(String topic, MqttMessage message) throws Exception {
                String payload = new String(message.getPayload());
                String titulo = payload.substring(0, payload.indexOf("\n"));
                System.out.println("mensagem receitas:" + titulo + " " + topic);
            }

            @Override
            public void deliveryComplete(IMqttDeliveryToken token) {

            }
        });

        MqttConnectOptions mqttConnectOptions = new MqttConnectOptions();
        mqttConnectOptions.setCleanSession(true);

        try {
            mqttAndroidClient.connect(mqttConnectOptions, null, new IMqttActionListener() {
                @Override
                public void onSuccess(IMqttToken asyncActionToken) {
                    System.out.println("Connection Success!");
                    try {
                        System.out.println("Subscribing to /test");
                        mqttAndroidClient.subscribe("/test", 0);
                        System.out.println("Subscribed to /test");
                    } catch (MqttException ex) {
                        System.out.println("MQTT Definicoes excpetion: " + ex);
                    }
                }

                @Override
                public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
                    System.out.println("MQTT Definicoes excpetion 2:" + exception.toString());
                }
            });
        } catch (MqttException ex) {
            System.out.println("MQTT Definicoes excpetion 3:" + ex.toString());
        }


        switchSaude = findViewById(R.id.switchSaude);
        switchAlimentacao = findViewById(R.id.switchAlimentacao);
        switchDesporto = findViewById(R.id.switchDesporto);

        Toolbar toolbar = findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        ActionBar actionBar = getSupportActionBar();
        actionBar.setDisplayHomeAsUpEnabled(true);

        setTitle("Definiçoes");

        switchAlimentacao.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            public void onCheckedChanged(CompoundButton View, boolean isChecked) {

                if(!isChecked){
                    Snackbar.make(View, "Cancelou a subscrição de dicas sobre Receitas", Snackbar.LENGTH_LONG).setAction("Action", null).show();
                }
                else
                {
                    topico = "Receitas";
                    try {
                        mqttAndroidClient.subscribe(topico, 1);
                    } catch (MqttException e) {
                        e.printStackTrace();
                    }
                    Snackbar.make(View, "Sobscreveu dicas sobre Receitas", Snackbar.LENGTH_LONG).setAction("Action", null).show();
                }
            }
        });

        switchDesporto.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            public void onCheckedChanged(CompoundButton View, boolean isChecked) {

                if(!isChecked){
                    Snackbar.make(View, "Cancelou a subscrição de dicas sobre Desporto", Snackbar.LENGTH_LONG).show();
                }
                else
                {
                    topico = "Desporto";
                    try {
                        mqttAndroidClient.subscribe(topico, 1);
                    } catch (MqttException e) {
                        e.printStackTrace();
                    }
                    Snackbar.make(View, "Sobscreveu dicas sobre Desporto", Snackbar.LENGTH_LONG).show();
                }
            }
        });

        switchSaude.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            public void onCheckedChanged(CompoundButton View, boolean isChecked) {

                if(!isChecked){
                    Snackbar.make(View, "Cancelou a subscrição de dicas sobre Saúde", Snackbar.LENGTH_LONG).show();
                }
                else
                {
                    topico = "Saúde";
                    try {
                        mqttAndroidClient.subscribe(topico, 1);
                    } catch (MqttException e) {
                        e.printStackTrace();
                    }
                    Snackbar.make(View, "Sobscreveu dicas sobre Saúde", Snackbar.LENGTH_LONG).show();
                }
            }
        });
    }


    @Override
    protected void onPause() {
        super.onPause();

        bundle.putBoolean("switchAlimentacaoState", switchAlimentacao.isChecked());
        bundle.putBoolean("switchDesportoState", switchDesporto.isChecked());
        bundle.putBoolean("switchSaudeState", switchSaude.isChecked());

    }

    @Override
    protected void onResume() {
        super.onResume();

        final MqttAndroidClient mqttAndroidClient = new MqttAndroidClient(this.getApplicationContext(), "tcp://5.196.27.244:1883", "users");

        if(bundle.getBoolean("switchAlimentacaoState")){
            switchAlimentacao.setChecked(bundle.getBoolean("switchAlimentacaoState"));
            topico = "Receitas";
            try {
                mqttAndroidClient.subscribe(topico, 1);
            } catch (MqttException e) {
                e.printStackTrace();
            }
        }

        if(bundle.getBoolean("switchDesportoState")){
            switchDesporto.setChecked(bundle.getBoolean("switchDesportoState"));
            topico = "Desporto";
            try {
                mqttAndroidClient.subscribe(topico, 1);
            } catch (MqttException e) {
                e.printStackTrace();
            }
        }

        if(bundle.getBoolean("switchSaudeState")){
            switchDesporto.setChecked(bundle.getBoolean("switchSaudeState"));
            topico = "Saúde";
            try {
                mqttAndroidClient.subscribe(topico, 1);
            } catch (MqttException e) {
                e.printStackTrace();
            }
        }
    }
}

My error:

12-27 12:06:30.264 20361-20361/com.support.android.iplfit E/AndroidRuntime: FATAL EXCEPTION: main Process: com.support.android.iplfit, PID: 20361 java.lang.RuntimeException: Unable to resume activity {com.support.android.iplfit/com.support.android.iplfit.Activities.DefinicoesActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'void org.eclipse.paho.android.service.MqttService.subscribe(java.lang.String, java.lang.String, int, java.lang.String, java.lang.String)' on a null object reference at android.app.ActivityThread.performResumeActivity(ActivityThread.java:3400) at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:3440) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2713) at android.app.ActivityThread.-wrap12(ActivityThread.java) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1460) at android.os.Handler.dispatchMessage(Handler.java:102) at android.os.Looper.loop(Looper.java:154) at android.app.ActivityThread.main(ActivityThread.java:6077) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:866) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:756) Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'void org.eclipse.paho.android.service.MqttService.subscribe(java.lang.String, java.lang.String, int, java.lang.String, java.lang.String)' on a null object reference at org.eclipse.paho.android.service.MqttAndroidClient.subscribe(MqttAndroidClient.java:906) at org.eclipse.paho.android.service.MqttAndroidClient.subscribe(MqttAndroidClient.java:841) at com.support.android.iplfit.Activities.DefinicoesActivity$3.onCheckedChanged(DefinicoesActivity.java:122) at android.widget.CompoundButton.setChecked(CompoundButton.java:156) at android.widget.Switch.setChecked(Switch.java:1074) at com.support.android.iplfit.Activities.DefinicoesActivity.onResume(DefinicoesActivity.java:213) at android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1269) at android.app.Activity.performResume(Activity.java:6766) at android.app.ActivityThread.performResumeActivity(ActivityThread.java:3377) at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:3440)  at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2713)  at android.app.ActivityThread.-wrap12(ActivityThread.java)  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1460)  at android.os.Handler.dispatchMessage(Handler.java:102)  at android.os.Looper.loop(Looper.java:154)  at android.app.ActivityThread.main(ActivityThread.java:6077)  at java.lang.reflect.Method.invoke(Native Method)  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:866)  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:756) 

来源:https://stackoverflow.com/questions/47992062/keep-mqtt-topics-subscribed-onresume-activity

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!