Coo*_*ova 7 service android mqtt paho
我正在开发的应用程序中实现Paho MQTT Android服务.在测试了Paho提供的示例应用程序之后,我发现有一些事情我想改变.
https://eclipse.org/paho/clients/android/
应用程序完全关闭后,应用程序服务似乎会关闭.我希望即使在应用程序关闭后,如果有更多消息进入,我也会保持服务运行.我也在寻找一种方法,一旦收到新消息,就可以将应用程序打开到特定的活动.
这是在消息到达时调用的回调之一,我尝试实现一个简单的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);
}
Run Code Online (Sandbox Code Playgroud)
虽然这似乎不是问题的完整解决方案,但我会发布我的解决方法以防万一.
对我来说,当用户从最近的应用列表中滑动应用时,问题就开始了.正如这里所提到的,这样的行为不仅杀死了活动,反而杀死了整个过程,包括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;
}
}
Run Code Online (Sandbox Code Playgroud)
服务器日志:
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)
Run Code Online (Sandbox Code Playgroud)
正如你所看到的那样,当我关闭应用程序并且服务被杀死时,它会重新启动重新连接并保持活动状态,然后才能找到它.从这里开始,你应该可以做其余的事情.也许使用新到的消息创建通知,这将打开应用程序.只记得在新创建的服务中做所有事情,保证保持连接.
如果您使用任务管理器关闭您的应用程序我不认为这是可能的,因为"完全关闭"应用程序也将停止它包含的任何服务.即使服务启动"粘性",它也不会在我的设备上重新启动.如果您通过在最近的任务上滑动它来关闭应用程序,则该服务仍会继续运行.有关详细信息,请参阅此处:从任务管理器中杀死Android应用程序会导致应用程序启动服务
但是,我认为另一个问题是,即使服务仍在运行,应用程序也包含服务调用的回调对象.如果应用程序不再运行,则回调不再存在,因此永远不会被调用.
以下是我如何实现这一点的高级视图.这已经在生产中运行了几个月但不幸的是我不拥有代码而无法发布.
MQTTService/ 的单例对象mqttAndroidClient.这会公开连接/断开连接的公共方法,并包含MqttCallback用于接收消息的对象.它还处理所需的连接丢失和重试机制.这是最棘手的部分,但我不能在这里发布.Application对象,我连接onCreate()并关闭连接onTerminate()BroadcastReceiver获取BOOT_COMPLETED驻留在Application对象中的操作,它有一个空的实现,但它会旋转应用程序,因此mqtt服务在启动时连接.这消除了运行任何给定活动以接收消息的需要.它对于关闭应用程序似乎也很有弹性,例外情况是如果你在应用程序设置中强行关闭它.这使得自从用户明确选择关闭它以来.
我知道这是这个问题的迟到答案,但我想分享我所做的事情,因为它可能会对某人有所帮助。
我创建了自己的Service来管理与代理的连接,并始终为每个 Android 设备维护一个连接实例。
重申该解决方案的特点:
该解决方案的主要特点:
startService(..)再次调用将触发其onStartCommand(). 在此方法中,我们只需检查该客户端是否已连接到代理,并根据需要进行连接/重新连接。在这里查看完整详细的答案。
| 归档时间: |
|
| 查看次数: |
10626 次 |
| 最近记录: |