8

開発中のアプリケーション内に Paho MQTT Android サービスを実装しています。Paho が提供するサンプル アプリケーションをテストした後、変更したい点がいくつかあることがわかりました。

https://eclipse.org/paho/clients/android/

アプリケーションが完全に閉じられると、アプリケーション サービスが停止したように見えます。さらにメッセージが届いた場合にアプリケーションを閉じた後でも、サービスを実行し続けたいと思います。また、新しいメッセージを受信したら、特定のアクティビティに対してアプリケーションを開く方法を探しています。

メッセージが到着したときに呼び出されるコールバックの 1 つを次に示します。単純な startActivity を実装して特定のアクティビティを開くことを試みましたが、アプリが閉じているか実行されていない場合は機能しません。

PAHO MQTT Android サービスを使用したことがある場合、アプリケーションが閉じられたときにサービスが停止しないようにする特定の方法はありますか? また、メッセージが届いたときにアプリケーションを再度開くにはどうすればよいですか?

    /**
   * @see org.eclipse.paho.client.mqttv3.MqttCallback#messageArrived(java.lang.String,
   *      org.eclipse.paho.client.mqttv3.MqttMessage)
   */
  @Override
  public void messageArrived(String topic, MqttMessage message) throws Exception {

    // Get connection object associated with this object
    Connection c = Connections.getInstance(context).getConnection(clientHandle);

    // create arguments to format message arrived notifcation string
    String[] args = new String[2];
    args[0] = new String(message.getPayload());
    args[1] = topic + ";qos:" + message.getQos() + ";retained:" + message.isRetained();

    // get the string from strings.xml and format
    String messageString = context.getString(R.string.messageRecieved, (Object[]) args);

    // create intent to start activity
    Intent intent = new Intent();
    intent.setClassName(context, "org.eclipse.paho.android.service.sample.ConnectionDetails");
    intent.putExtra("handle", clientHandle);

    // format string args
    Object[] notifyArgs = new String[3];
    notifyArgs[0] = c.getId();
    notifyArgs[1] = new String(message.getPayload());
    notifyArgs[2] = topic;

    // notify the user
    Notify.notifcation(context, context.getString(R.string.notification, notifyArgs), intent,
        R.string.notifyTitle);

    // update client history
    c.addAction(messageString);

    Log.e("Message Arrived", "MESSAGE ARRIVED CALLBACK");

    // used to open the application if it is currently not active
    Intent i = new Intent(context, ConnectionDetails.class);
    i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    i.putExtra("handle", clientHandle);
    context.startActivity(i);


  }
4

4 に答える 4

7

これは問題の完全な解決策のようには思えませんが、誰かの助けになる場合に備えて、回避策を投稿します。

私にとって、問題は、ユーザーが最近のアプリのリストからアプリをスワイプしたときに始まります。ここで述べたように、このようなアクションはアクティビティを強制終了するだけでなく、MqttService. 次に、スレッドで述べたように、Android はサービスを再起動する必要があることを認識し、強制終了されたサービスの再起動をスケジュールします。ただし、すべての接続がアクティビティにバインドされているため、これは接続の回復を意味するものではありません。

したがって、サービス停止の問題を解消する方法を見つけない限り、ユーザーがアプリをスワイプすることを決定したときに、ブローカーへの接続が失われることが保証されます。

ただし、接続が失われた後でも簡単に再接続できるため、これで世界が終わるわけではありません。問題は、今回は目的のアクションを実行するアクティビティがないことです。Paho Android サービス ライブラリのソース コードを修正するか、私が行ったより単純な方法で別のサービスを作成する必要があります。

すべての接続はこの新しいサービスで行われ、接続を希望するすべてのアクティビティはこのサービスと通信する必要があります。これの利点は、サービスを固定できることです。ユーザーがアプリをスワイプして強制終了した場合でも、すぐに再起動し、再接続するだけで回復できます。

この非常に単純なサービスのデモンストレーションとして:

public class MessagingService extends Service {
    private static final String TAG = "MessagingService";
    private MqttAndroidClient mqttClient;
    String deviceId;



    @Override
    public void onCreate() {
    }
    private void setClientID() {
        WifiManager wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
        WifiInfo wInfo = wifiManager.getConnectionInfo();
        deviceId = wInfo.getMacAddress();
        if (deviceId == null) {
            deviceId = MqttAsyncClient.generateClientId();
        }
    }

    public class MsgBinder extends Binder {
        public MsgServ getService() {
            return MsgServ.this;
        }
    }

    public void doConnect(){
        // Using some of the Paho sample app classes
        String server = ConfigClass.BROKER_URI;
        MemoryPersistence mem = new MemoryPersistence();
        mqttClient = new MqttAndroidClient(this,ConfigClass.BROKER_URI,deviceId,mem);
        MqttConnectOptions conOpt = new MqttConnectOptions();
        String clientHandle = server + deviceId;
        Connection con = new Connection(clientHandle, deviceId, ConfigClass.BROKER_ADDRESS,
                                        ConfigClass.BROKER_PORT, this, mqttClient, false);
        conOpt.setCleanSession(false);
        conOpt.setConnectionTimeout(ConfigClass.CONN_TIMEOUT);
        conOpt.setKeepAliveInterval(ConfigClass.CONN_KEEPALIVE);
        conOpt.setUserName("testclient");
        conOpt.setPassword("password".toCharArray());
        String[] actionArgs = new String[1];
        actionArgs[0] = deviceId;
        final ActionListener callback =
                new ActionListener(this, ActionListener.Action.CONNECT, clientHandle,
                                   actionArgs);
        mqttClient.setCallback(new MqttCallbackHandler(this, clientHandle));
        mqttClient.setTraceCallback(new MqttTraceCallback());
        con.addConnectionOptions(conOpt);
        Connections.getInstance(this).addConnection(con);
        try {
            mqttClient.connect(conOpt, null, callback);
            Log.d("Con", "Connected");
        } catch (MqttException e) {
            Log.d("Con", "Connection failed");
            e.printStackTrace();
        }
    }

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

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        doConnect();
        return START_STICKY;
    }

}

サーバーのログ:

1433455371: New client connected from 192.168.2.5 as ed:0a:2b:56:b5:45 (c0, k30, u'testclient').
1433455371: Sending CONNACK to ed:0a:2b:56:b5:45 (1, 0)
1433455375: Socket error on client ed:0a:2b:56:b5:45, disconnecting.
1433455377: New connection from 192.168.2.5 on port 1883.
1433455377: Client ed:0a:2b:56:b5:45 disconnected.
1433455377: New client connected from 192.168.2.5 as ed:0a:2b:56:b5:45 (c0, k30, u'testclient').
1433455377: Sending CONNACK to ed:0a:2b:56:b5:45 (1, 0)

ご覧のとおり、アプリを閉じてサービスが終了するとすぐに、再起動して再接続し、後で見つけるだけでキープアライブになります。ここから、残りを実行できるはずです。おそらく、新しく到着したメッセージでアプリを開く通知を作成します。接続を維持することが保証されている、新しく作成されたサービスですべてを行うことを忘れないでください。

于 2015-06-04T22:11:14.307 に答える
2

これがこの質問に対する遅い回答であることは知っていますが、誰かの助けになるかもしれないので、私がやったことを共有したいと思います.

Serviceブローカーへの接続を管理し、Android デバイスごとに 1 つの接続されたインスタンスを常に維持するために独自のものを作成しました。

ソリューションの機能を繰り返します。

このソリューションの主な機能:

  1. サービスは、存続している限り単一のインスタンスを維持します。
  2. サービスが強制終了された場合、Android はサービスを再起動します (START_STICKY のため)。
  3. デバイスの起動時にサービスを開始できます。
  4. サービスはバックグラウンドで実行され、通知を受信するために常に接続されています。
  5. startService(..)サービスが有効な場合、もう一度呼び出すと、そのonStartCommand(). このメソッドでは、このクライアントがブローカーに接続されているかどうかを確認し、必要に応じて接続/再接続します。

ここで完全に詳細な回答を確認してください。

于 2016-12-09T12:40:18.893 に答える
1

Eclipse Paho は、これを行うために必要なものをすべて提供してくれると思います。アプリをスワイプでき、サービスが実行されています。詳細については、Paho MQTT Android service wake up activityでの私の回答をご覧ください。

お役に立てば幸いです。

于 2015-07-08T08:30:04.763 に答える