Опубликовать намерение общего ресурса на сервере MQTT - PullRequest
0 голосов
/ 15 марта 2019

Я пытаюсь создать приложение 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 голосов
/ 15 марта 2019

Ну, я нашел решение (возможно, не лучшее), используя режим singleTask (новый атрибут android:launchMode="singleTask" тега activity в AndroidManifest.xml) и метод onNewIntent:

    @Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        Log.d(logTag, "Get new intent...");

        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, a new intent!");
            }
        }

    }

Больше нет ошибки, когда я публикую сообщение при получении намерения. Спасибо за Блог Cheese Factory , который помог мне понять режим запуска активности Android.

0 голосов
/ 15 марта 2019

Это основная проблема - 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();
    }
}
...