首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Paho MQTT Android服务问题

Paho MQTT Android服务问题
EN

Stack Overflow用户
提问于 2015-02-16 14:25:09
回答 4查看 13.6K关注 0票数 8

我正在开发的一个应用程序中实现Paho MQTT Android服务。在测试了泛美卫生组织提供的示例应用程序之后,我发现有几件事情我想要改变。

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

应用程序完全关闭后,应用程序服务似乎会关闭。即使在应用程序关闭之后,如果出现更多消息,我也希望保持服务的运行。我也在寻找一种方法,打开应用程序到一个特定的活动,一旦收到一个新的消息。

下面是消息到达时调用的回调之一,我尝试实现一个简单的startActivity来打开特定的活动,但是如果应用程序关闭/不再运行,它就不能工作。

如果有人使用过PAHO MQTT Android服务,那么在应用程序关闭时,是否有一种特定的方法来防止服务停止,以及当消息到达时我如何重新打开应用程序?

代码语言:javascript
复制
    /**
   * @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);


  }
EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2016-12-09 12:40:18

我知道这是对这个问题迟来的回答,但我想分享一下我所做的,因为它可能会对某人有所帮助。

我创建了自己的Service来管理到代理的连接,并且总是维护每个android设备一个连接的实例。

重申解决办法的特点:

该解决方案的主要特点:

  1. 只要服务还活着,它就会维护一个实例。
  2. 如果服务被终止,Android将重新启动它(因为START_STICKY)
  3. 可以在设备启动时启动服务。
  4. 服务在后台运行,并始终连接到接收通知。
  5. 如果服务是活动的,再次调用startService(..)将触发它的onStartCommand()。在此方法中,我们只需检查此客户端是否连接到代理,如果需要,则进行连接/重新连接。

查看完全详细的答案here

票数 2
EN

Stack Overflow用户

发布于 2015-06-04 22:11:14

虽然这似乎不是一个完整的解决问题的办法,我会张贴我的解决办法,以防它帮助别人。

对我来说,当用户将应用程序从最近的应用列表中删除时,问题就开始了。正如前面提到的,这样的操作不仅杀死了活动,反而扼杀了整个过程,包括here。然后,正如线程中提到的,Android认识到您的服务应该重新启动,并计划重新启动已终止的服务。但是,这并不意味着连接恢复,因为所有连接都绑定到活动。

因此,除非您找到了消除服务停止问题的方法,否则当用户决定删除应用程序时,您肯定会失去与代理的连接。

然而,这并不是世界末日,因为我们可以简单地在失去连接后重新连接。问题是,这一次我们没有一个活动来执行所需的操作。您要么修改Paho Android服务库的源代码,要么以一种简单得多的方式创建另一个服务。

所有连接都将在这个新服务中进行,任何希望连接的活动都应该与此服务进行通信。这样做的好处是我们可以让服务变得粘稠,即使用户刷掉我们的应用程序,它也会立即重新启动,我们可以通过简单的重新连接来恢复。

因此,作为一个非常简单的服务的演示:

代码语言:javascript
复制
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;
    }

}

服务器的日志:

代码语言:javascript
复制
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)

正如你所看到的,一旦我关闭了应用程序,服务就被关闭了,它就会重新启动、重新连接并保持生命--然后再找到它。从现在起,你应该能做剩下的事了。也许会用你新到的消息创建一个通知,这将打开应用程序。只需记住在新创建的服务中执行所有的操作,这保证了连接的维护。

票数 7
EN

Stack Overflow用户

发布于 2015-02-20 20:00:09

如果您使用任务管理器关闭应用程序,我认为这是不可能的,因为“完全关闭”应用程序也会停止它包含的任何服务。即使服务是启动“粘稠”的,它不会在我的设备上重新启动。如果你通过在最近的任务上滑动它来关闭这个应用程序,那么这个服务就会继续运行。有关更多信息,请参见这里:Killing android application from task manager kills services started by app

但是,我认为另一个问题是,即使服务仍然在运行,应用程序也包含由服务调用的回调对象。如果应用程序不再运行,则回调不再存在,因此永远不会被调用。

下面是我如何实现这个的高级视图。这已经在生产中运行了几个月,但不幸的是,我没有自己的代码,也不能发布它。

  • 我创建了一个承载MQTTService/mqttAndroidClient的单例对象。这将公开连接/断开连接的公共方法,并包含用于接收消息的MqttCallback对象。它还处理所需的连接丢失和重试机制。这是最棘手的部分,但我不能把它张贴在这里。
  • 我创建了一个Application对象,我用onCreate()连接并关闭onTerminate()中的连接
  • 我注册了一个BroadcastReceiver,它获取驻留在Application对象中的BOOT_COMPLETED操作,它有一个空的实现,但它可以将应用程序拆分,以便mqtt服务在引导时连接。

这就不需要运行任何给定的活动来接收消息。对于关闭应用程序,它似乎也具有弹性,但在应用程序设置中“强制关闭”则是例外。这使得虽然用户显式地选择关闭它。

票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/28543569

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档