MQTT based on the use of Android

Foreword

Previous MQTT mentioned general way, since the network project of frequent fluctuations in smart home TV, common approach has been unable to meet demand, often resulting in duplication subscribe to receive more than one message, it can only open a new path, and finally found MqttAndroidClient dream.

1. Integration

And on an integrated approach and the use of MQTT Introduction to New configuration, build.gradle new

 

implementation 'org.eclipse.paho:org.eclipse.paho.android.service:1.1.1'

manifest file which requires registration service

 

<!-- Mqtt Service -->
        <service android:name="org.eclipse.paho.android.service.MqttService" />

2.MqttAndroidClient important source parsing

MqttAndroidClient is designed to expand the repackaged MQTTClient classes, including subscription, multi-threading and is connected directly to the package to see MqttAndroidClient source connected to the non-critical code has been omitted

 

    public IMqttToken connect(MqttConnectOptions options, Object userContext,
            IMqttActionListener callback) throws MqttException {
        if (mqttService == null) { 
        }
        else {
            pool.execute(new Runnable() {
                @Override
                public void run() {
                    doConnect();
                }
            });
        }
        return token;
    }

doConnect () operation on the sub-thread connection, effectively prevent fluctuations in the network connection block the main thread prolonged

 

private void doConnect() {
        ...
            mqttService.connect(clientHandle, connectOptions, null,
                    activityToken);
        ...
    }

Ali specifically written for Android client a MQTTService, convenient unified management, in addition to connecting operation, reconnect, disconnect is done in MQTTService in.

 

public void connect(String clientHandle, MqttConnectOptions connectOptions,
      String invocationContext, String activityToken)throws MqttSecurityException, MqttException {
        MqttConnection client = getConnection(clientHandle);
        client.connect(connectOptions, null, activityToken);
  }

 

public void connect(MqttConnectOptions options, String invocationContext,
            String activityToken) {
            ...
            if (myClient != null) {
                if (isConnecting ) {
                }else if(!disconnected){
                }
                else {                  
                    service.traceDebug(TAG, "myClient != null and the client is not connected");
                    service.traceDebug(TAG,"Do Real connect!");
                    setConnectingState(true);
                    myClient.connect(connectOptions, invocationContext, listener);
                }
            }
            ...
    }

 

public IMqttToken connect(MqttConnectOptions options, Object userContext, IMqttActionListener callback)throws MqttException, MqttSecurityException {
        final String methodName = "connect";
        if (comms.isConnected()) {
            throw ExceptionHelper.createMqttException(MqttException.REASON_CODE_CLIENT_CONNECTED);
        }
        if (comms.isConnecting()) {
            throw new MqttException(MqttException.REASON_CODE_CONNECT_IN_PROGRESS);
        }
        if (comms.isDisconnecting()) {
            throw new MqttException(MqttException.REASON_CODE_CLIENT_DISCONNECTING);
        }
        if (comms.isClosed()) {
            throw new MqttException(MqttException.REASON_CODE_CLIENT_CLOSED);
        }
        ...
        connectActionListener.connect();
        return userToken;
    }

Source itself for isConnected, isConnecting, isDisconnecting, isClosed do exception handling to avoid connection resulting in duplication connection is being connected or disconnected. No later posted the source code necessary, is to open a connection thread.

3.MqttAndroidClient use

To complete the connection line of code MQTT

 

mqttAndroidClient.connect(mqttConnectOptions, null, iMqttActionListener);

Of course, this is not enough, found that in practical applications there is a problem, after some time off network reconnection MQTT network does not automatically reconnect, so we have to do manual optimization. The idea is very simple, open reconnection threads node disconnected, reconnect thread closed after a successful connection. The following is the complete code stickers, the main attention before reconnection mechanism and remember to subscribe unsubscribe and then subscribe. (Section contains its own code, you can ignore, notes in great detail)

 

public class MQTTManager {

    private Context mContext;
    private MqttAndroidClient mqttAndroidClient;
    private String clientId;//自定义

    private MqttConnectOptions mqttConnectOptions;

    private ScheduledExecutorService reconnectPool;//重连线程池

    public MQTTManager(Context mContext) {
        this.mContext = mContext;
    }

    public void buildClient() {
        closeMQTT();//先关闭上一个连接

        buildMQTTClient();
    }

    private IMqttActionListener iMqttActionListener = new IMqttActionListener() {
        @Override
        public void onSuccess(IMqttToken asyncActionToken) {
            TVLog.i("connect-"+"onSuccess");
            closeReconnectTask();
            subscribeToTopic();
        }

        @Override
        public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
            //connect-onFailure-MqttException (0) - java.net.UnknownHostException
            TVLog.i("connect-"+ "onFailure-"+exception);
            startReconnectTask();
        }
    };

    private MqttCallback mqttCallback = new MqttCallback() {
        @Override
        public void connectionLost(Throwable cause) {
            //close-connectionLost-等待来自服务器的响应时超时 (32000)
            //close-connectionLost-已断开连接 (32109)
            TVLog.i("close-"+"connectionLost-"+cause);
            if (cause != null) {//null表示被关闭
                startReconnectTask();
            }
        }

        @Override
        public void messageArrived(String topic, MqttMessage message) throws Exception {
            String body = new String(message.getPayload());
            TVLog.i("messageArrived-"+message.getId()+"-"+body);
        }

        @Override
        public void deliveryComplete(IMqttDeliveryToken token) {
            try {
                TVLog.i("deliveryComplete-"+token.getMessage().toString());
            } catch (MqttException e) {
                e.printStackTrace();
            }
        }
    };

    private void buildMQTTClient(){
        mqttAndroidClient = new MqttAndroidClient(mContext, MQTTCons.Broker, clientId);
        mqttAndroidClient.setCallback(mqttCallback);

        mqttConnectOptions = new MqttConnectOptions();
        mqttConnectOptions.setConnectionTimeout(10);
        mqttConnectOptions.setKeepAliveInterval(20);
        mqttConnectOptions.setCleanSession(true);
        try {
            mqttConnectOptions.setUserName("Signature|" + MQTTCons.AcessKey + "|" + MQTTCons.instanceId);
            mqttConnectOptions.setPassword(MacSignature.macAndSignature(clientId, MQTTCons.SecretKey).toCharArray());
        } catch (Exception e) {
        }
        doClientConnection();
    }

    private synchronized void startReconnectTask(){
        if (reconnectPool != null)return;
        reconnectPool = Executors.newScheduledThreadPool(1);
        reconnectPool.scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                doClientConnection();
            }
        } , 0 , 5*1000 , TimeUnit.MILLISECONDS);
    }

    private synchronized void closeReconnectTask(){
        if (reconnectPool != null) {
            reconnectPool.shutdownNow();
            reconnectPool = null;
        }
    }

    /**
     * 连接MQTT服务器
     */
    private synchronized void doClientConnection() {
        if (!mqttAndroidClient.isConnected()) {
            try {
                mqttAndroidClient.connect(mqttConnectOptions, null, iMqttActionListener);
                TVLog.d("mqttAndroidClient-connecting-"+mqttAndroidClient.getClientId());
            } catch (MqttException e) {
                e.printStackTrace();
            }
        }
    }

    private void subscribeToTopic() {//订阅之前会取消订阅,避免重连导致重复订阅
        try {
            String registerTopic = "";//自定义
            String controlTopic = "";//自定义
            String[] topicFilter=new String[]{registerTopic , controlTopic };
            int[] qos={0,0};
            mqttAndroidClient.unsubscribe(topicFilter, null, new IMqttActionListener() {
                @Override
                public void onSuccess(IMqttToken asyncActionToken) {
                    TVLog.i("unsubscribe-"+"success");
                }

                @Override
                public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
                    TVLog.i("unsubscribe-"+"failed-"+exception);
                }
            });
            mqttAndroidClient.subscribe(topicFilter, qos, null, new IMqttActionListener() {
                @Override
                public void onSuccess(IMqttToken asyncActionToken) {//订阅成功
                    TVLog.i("subscribe-"+"success");
                }

                @Override
                public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
//                    startReconnectTask();
                    TVLog.i("subscribe-"+"failed-"+exception);
                }
            });

        } catch (MqttException ex) {
        }
    }

    public void sendMQTT(String topicSep, String msg) {
        try {
            if (mqttAndroidClient == null)return;
            MqttMessage message = new MqttMessage();
            message.setPayload(msg.getBytes());
            String topic = "";//自定义
            mqttAndroidClient.publish(topic, message, null, new IMqttActionListener() {
                @Override
                public void onSuccess(IMqttToken asyncActionToken) {
//                    TVLog.i("sendMQTT-"+"success:" + msg);
                }

                @Override
                public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
//                    startReconnectTask();
                    TVLog.i("sendMQTT-"+"failed:" + msg);
                }
            });
        } catch (MqttException e) {
        }
    }

    public void closeMQTT(){
        closeReconnectTask();
        if (mqttAndroidClient != null){
            try {
                mqttAndroidClient.unregisterResources();
                mqttAndroidClient.disconnect();
                TVLog.i("closeMQTT-"+mqttAndroidClient.getClientId());
                mqttAndroidClient = null;
            } catch (MqttException e) {
                e.printStackTrace();
            }
        }
    }

}

Called by and wanted to make thread-safe singleton can own package

 

if (mqttManager == null)
            mqttManager = new MQTTManager(getApplicationContext());
mqttManager.buildClientId();

Epilogue

Android-based part can be considered the end, which is also mixed with some source explained that follow-up will write more about parsing the source code.



Reprinted: https: //www.jianshu.com/p/2857419d14b0

Published 40 original articles · won praise 57 · Views 250,000 +

Guess you like

Origin blog.csdn.net/With__Sunshine/article/details/105317659