Paho MQTT Android服务问题

我正在开发一个应用程序内部实现Paho MQTT Android服务。 在testing了Paho提供的示例应用程序之后,我发现我想改变一些东西。

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

一旦应用程序完全closures,应用程序服务就会closures。 即使在应用程序closures之后,我仍然希望保持服务正常运行。如果收到更多消息,我也正在寻找一种方法,一旦接收到新消息,就可以将应用程序打开到特定的活动。

这里是一个消息到达时调用的callback之一,我试图实现一个简单的startActivity打开一个特定的活动,但如果应用程序closures/不再运行,它不工作。

如果有人使用了PAHO MQTT Android服务,有没有一个特定的方法来保持应用程序closures时停止服务,以及当消息到达时如何重新打开应用程序?

/** * @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); } 

Solutions Collecting From Web of "Paho MQTT Android服务问题"

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

我创build了自己的Service来pipe理与代理的连接,并始终为每个Android设备维护一个连接的实例。

重申解决scheme的function:

此解决scheme的主要特点:

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

看看这里的 详细答案。

虽然这似乎不是一个完整的解决scheme,我会发布我的解决方法,以防万一它有助于某人。

对于我来说,当用户将应用程序从最近的应用程序列表中拖出时,问题就开始了。 正如这里提到的,这样的行为不仅杀死了这个活动,反而会杀死整个过程,包括MqttService 。 然后,正如线程中提到的Android认识到,您的服务应该重新启动,并安排重新启动死亡的服务。 但是,这并不意味着连接恢复,因为所有连接都绑定到活动。

因此,除非您find解决服务停止问题的方法,否则当用户决定刷出应用程序时,您将保证与代理失去连接。

然而,这并不是世界末日,因为我们可以在我们失去联系之后重新build立联系。 问题是,这次我们没有一个活动去做所需的行动。 您必须修改Paho Android服务库的源代码,或者以更简单的方式修改我创build的另一个服务。

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

所以作为这个非常简单的服务的示范:

 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) 

正如你可以看到,一旦我closures应用程序和服务被杀害,它重新启动重新连接,并保持活着只是后来find。 从这里,你应该可以做剩下的事情。 也许创build一个通知与您新来的消息,将打开应用程序。 只要记得在新创build的服务中做所有事情,保证连接。

如果你closures你的应用程序使用任务pipe理器,我不认为这是可能的,因为“完全closures”应用程序也将停止它包含的任何服务。 即使服务启动“粘滞”,它不会在我的设备上重新启动。 如果您通过在最近的任务中将其刷掉,closures该应用程序,该服务将继续运行。 在这里看到更多的信息: 从任务pipe理器杀死android应用程序杀死由应用程序启动的服务

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

这是我如何实现这个的高层次的看法。 这已经在生产中运行了几个月,但不幸的是我不拥有的代码,不能发布。

  • 我创build了一个承载MQTTService / mqttAndroidClient的单例对象。 这暴露了连接/断开的公共方法,并包含用于接收消息的MqttCallback对象。 它还处理丢失的连接和重试机制。 这是最棘手的部分,但我不能在这里发布。
  • 我创build了一个Application对象,我在onCreate()中连接并closuresonTerminate()
  • 我注册了一个BroadcastReceiver ,它获得驻留在Application对象中的BOOT_COMPLETED操作,它有一个空的实现,但是它启动了应用程序,所以mqtt服务在启动时连接。

这消除了运行任何给定的活动来接收消息的需要。 对于closures应用程序来说,它似乎也很有弹性,例外情况是如果您在应用程序设置中强制closures应用程序。 这使得自从用户明确selectclosures它。

我认为Eclipse Paho为您提供了所需的全部function。 我可以刷我的应用程序,我的服务正在运行。 有关更多详细信息,请参阅Paho MQTT Android服务唤醒活动的答案

我希望这会帮助你。