在MQTT服务器上发布共享意向

时间:2019-03-14 21:35:07

标签: android mqtt publish-subscribe paho

我正在尝试创建一个Android应用程序,该应用程序从其他应用程序接收一些文本(使用共享意图),并将其发送到MQTT服务器上。

我正在使用Eclipse Paho库和Android示例,该示例发布按钮操作中的文本并记录订阅主题中的文本。该示例工作正常。

但是,当我尝试添加一些代码来处理共享意图时,当我尝试发布文本时,应用程序崩溃。

这是Java代码:

package net.example.testingmqtt;
import android.content.Intent;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.View;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Toast;

import org.eclipse.paho.android.service.MqttAndroidClient;
import org.eclipse.paho.client.mqttv3.IMqttActionListener;
import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.IMqttToken;
import org.eclipse.paho.client.mqttv3.MqttCallbackExtended;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage;


public class MainActivity extends AppCompatActivity {

    MqttAndroidClient mqttAndroidClient;

    final String serverUri = "tcp://iot.eclipse.org:1883";

    String clientId = "AndroidClient";
    final String subscriptionTopic = "topic";
    final String publishTopic = "pubtopic";

    final String logTag = "MqttLog";


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        FloatingActionButton fab = findViewById(R.id.fab);
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                publishMessage("Hello from Android");
            }
        });

        // Setup MQTT
        setupMqtt();

        // Intent
        Intent intent = getIntent();
        String action = intent.getAction();
        String type = intent.getType();

        if(Intent.ACTION_SEND.equals(action) && type != null) {
            if("text/plain".equals(type)) {
                String sharedText = intent.getStringExtra(Intent.EXTRA_TEXT);
                Log.d(logTag, "Get text/plain intent: " + sharedText);
                publishMessage("Oh");  // -- This is the problem!
            }
        }

    }

    public void setupMqtt() {

        clientId = clientId + System.currentTimeMillis();

        mqttAndroidClient = new MqttAndroidClient(getApplicationContext(), serverUri, clientId);
        mqttAndroidClient.setCallback(new MqttCallbackExtended() {
            @Override
            public void connectComplete(boolean reconnect, String serverURI) {
                if (reconnect) {
                    Log.d(logTag, "Reconnected to " + serverURI);
                    subscribeToTopic();
                }
                else {
                    Log.d(logTag, "Connected to " + serverURI);
                }
            }

            @Override
            public void connectionLost(Throwable cause) {
                Log.d(logTag, "The connection was lost");

            }

            @Override
            public void messageArrived(String topic, MqttMessage message) throws Exception {
                String msg = new String(message.getPayload());
                Log.d(logTag, "Incoming message: " + msg);
                Toast.makeText(MainActivity.this, msg, Toast.LENGTH_SHORT).show();
            }

            @Override
            public void deliveryComplete(IMqttDeliveryToken token) {

            }
        });

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

        Log.d(logTag, "Trying to connect to MQTT server...");
        try {
            mqttAndroidClient.connect(mqttConnectOptions, null, new IMqttActionListener() {
                @Override
                public void onSuccess(IMqttToken asyncActionToken) {
                    subscribeToTopic();
                }

                @Override
                public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
                    Log.w(logTag, "Failed to connect to " + serverUri);

                }
            });

        } catch (MqttException ex) {
            ex.printStackTrace();
        }

    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }

    public void subscribeToTopic() {
        try {
            mqttAndroidClient.subscribe(subscriptionTopic, 0, null, new IMqttActionListener() {
                @Override
                public void onSuccess(IMqttToken asyncActionToken) {
                    Log.d(logTag, "Subscribed");
                }

                @Override
                public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
                    Log.w(logTag, "Failed to subscribe");
                }
            });
        } catch (MqttException ex) {
            ex.printStackTrace();
        }
    }

    public void publishMessage(String text) {
        try {
            MqttMessage message = new MqttMessage();
            message.setPayload(text.getBytes());
            mqttAndroidClient.publish(publishTopic, message);
            Log.d(logTag, "Message published");
        } catch (MqttException ex) {
            ex.printStackTrace();
        }
    }
}

publishMessage("Oh")返回一个异常:

2019-03-14 22:15:44.579 19507-19507/net.e.testingmqtt E/AndroidRuntime: FATAL EXCEPTION: main
    Process: net.example.testingmqtt, PID: 19507
    java.lang.NullPointerException: Attempt to invoke virtual method 'org.eclipse.paho.client.mqttv3.IMqttDeliveryToken org.eclipse.paho.android.service.MqttService.publish(java.lang.String, java.lang.String, org.eclipse.paho.client.mqttv3.MqttMessage, java.lang.String, java.lang.String)' on a null object reference
        at org.eclipse.paho.android.service.MqttAndroidClient.publish(MqttAndroidClient.java:812)
        at org.eclipse.paho.android.service.MqttAndroidClient.publish(MqttAndroidClient.java:668)
        at net.example.testingmqtt.MainActivity.publishMessage(MainActivity.java:177)
        at net.example.testingmqtt.MainActivity$1.onClick(MainActivity.java:48)
        at android.view.View.performClick(View.java:6891)
        at android.view.View$PerformClick.run(View.java:26083)
        at android.os.Handler.handleCallback(Handler.java:789)
        at android.os.Handler.dispatchMessage(Handler.java:98)
        at android.os.Looper.loop(Looper.java:164)
        at android.app.ActivityThread.main(ActivityThread.java:6938)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:327)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1374)

我知道启动应用程序时(使用共享意图后),MQTT连接没有建立。但是我不明白为什么在这种情况下,上一条语句(setupMqtt)不能建立连接。

您对修改代码有何建议?

2 个答案:

答案 0 :(得分:0)

这是一个基本问题-NPE又名NullPointerException:-)

您正在尝试调用mqttAndroidClient.publish(publishTopic, message),但是mqttAndroidClient尚未初始化(由您使用setupMqtt方法),因此为空。

您可以添加一个if (mqttAndroidClient != null)条件,或者只是捕获并忽略NPE:

public void publishMessage(String text) {
    try {
        MqttMessage message = new MqttMessage();
        message.setPayload(text.getBytes());
        mqttAndroidClient.publish(publishTopic, message);
        Log.d(logTag, "Message published");
    } catch (NullPointerException | MqttException ex) {
        ex.printStackTrace();
    }
}

答案 1 :(得分:0)

好吧,我通过使用singleTask模式(android:launchMode="singleTask"activity标签的新AndroidManifest.xml属性)和{{ 1}}方法:

onNewIntent

收到意图后,发布消息时没有更多错误。 感谢The Cheese Factory Blog帮助我了解Android活动启动模式。