Проблема с сервисом Paho MQTT Android
я реализую службу Paho MQTT Android в приложении, которое я разрабатываю. После тестирования примера приложения, предоставленного Паоз, я обнаружил, что есть несколько вещей, которые я хотел бы изменить.
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);
}
4 ответов
Я знаю, что это поздний ответ на этот вопрос, но я хотел бы поделиться тем, что я сделал, поскольку это может помочь кому-то.
Я создал свой собственный Service
для управления подключением к брокеру и всегда поддерживать один подключенный экземпляр на android устройства.
повторяя особенности решения:
основные характеристики этого решения:
- служба поддерживает один экземпляр до тех пор, пока он живой.
- если служба убита, Android перезапускает ее (потому что START_STICKY)
- сервис может быть запущен при загрузке устройства.
- служба работает в фоновом режиме и всегда подключена для получения уведомлений.
- если служба жива, вызов
startService(..)
снова вызовет ееonStartCommand()
. В этом методе мы просто проверяем, подключен ли этот клиент к брокеру, и при необходимости подключаемся/переподключаемся.
проверить полностью полная ответ здесь.
хотя это не кажется полным решением проблемы, я опубликую свой обходной путь, если это кому-то поможет.
для меня проблема начинается, когда пользователь удаляет приложение из списка последних приложений. Как уже упоминалось здесь такое действие не только убивает активность, но и убивает весь процесс, включая MqttService
. Затем, как уже упоминалось в потоке Android признает, что ваш сервис должен быть перезапущен и планирует перезапуск убитых услуга. Однако это не означает восстановления соединения, поскольку все соединения были привязаны к действию.
поэтому, если вы не найдете способ устранить проблему остановки службы, вы гарантированно потеряете соединение с брокером, когда пользователь решит провести приложение.
Это не конец света, однако, как мы можем просто восстановить после того, как мы потеряли связь. Проблема, на этот раз у нас нет активности, чтобы сделать желаемое действие. Вы должны либо измените исходный код служебной библиотеки 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)
как вы можете видеть, как только я закрываю приложение, и служба убивается, он перезапускает переподключается и остается в живых, просто найдите потом. Отсюда вы сможете сделать все остальное. Возможно, создание уведомления с вновь прибывшим сообщением, которое откроет приложение. Просто не забудьте сделать все в недавно созданной службе, которая гарантированно поддерживает соединение.
если вы закрываете приложение с помощью Диспетчера задач, я не думаю, что это возможно, так как "полное закрытие" приложение также остановит любые службы, которые оно содержит. Несмотря на то, что служба запущена "липкой", она не перезапускается на моем устройстве. Если вы закрываете приложение, проводя его по последним задачам, служба остается запущенной. См. здесь для получения дополнительной информации:убийство android-приложения из Диспетчера задач убивает службы, запущенные приложением
однако, я думаю, что другой проблема в том, что даже если служба все еще работает, приложение содержит объекты обратного вызова, которые вызываются службой. Если приложение больше не работает обратный вызов больше не существует и, следовательно, никогда не вызывается.
вот высокий уровень представления о том, как я реализовал это. Это работает в производстве в течение нескольких месяцев, но, к сожалению, я не владею кодом и не могу опубликовать его.
- я создал одноэлементный объект, в котором размещается
MQTTService
/mqttAndroidClient
. Это предоставляет общедоступные методы для подключения / отключения и содержитMqttCallback
объект, используемый для получения сообщений. Он также обрабатывает потерянное соединение и повторяет необходимые механизмы. Это самая сложная часть, но я не могу опубликовать ее здесь. - я создал
Application
объект, я подключаюсь вonCreate()
и закройте соединение вonTerminate()
- я зарегистрировал
BroadcastReceiver
получаетBOOT_COMPLETED
действие, которое находится вApplication
"объект", он пустой реализация, но она запускает приложение, поэтому служба mqtt подключается при загрузке.
это устраняет необходимость в любой заданной деятельности для получения сообщения. Он также кажется устойчивым к закрытию приложения, исключением является то, что вы "принудительно закрываете" его в настройках приложения. Это делает так, хотя, поскольку пользователь явно решил закрыть его.
Я думаю, что Eclipse Paho приносит все, что вам нужно для этого. Я могу провести свое приложение, и моя служба запущена. Для более подробной информации посмотрите мой ответ на Пахо MQTT Android Сервис пробуждение активность
Я надеюсь, что это поможет вам.