Android频繁地终止服务
我们准备了一个Android应用程序,该应用程序带有一个与服务器保持MQTT连接的服务。该服务从onstart命令返回一个*START\u STICKY*,以便Android在因资源短缺而终止服务时重新启动该服务。但问题是,这项服务经常被Android操作系统扼杀。它有时会在几秒钟内终止服务一次,即使设备上没有其他进程工作(内存为2GB)。为什么Android如此频繁地终止我的服务?如何减少重新启动的次数?我的服务应该被尽可能少地终止,因为它断开了我的tcp连接,客户端必须重新连接,这会在我们的服务器上造成相当大的负载。此代码可能有什么问题?谢谢Android频繁地终止服务,android,tcp,android-service,mqtt,Android,Tcp,Android Service,Mqtt,我们准备了一个Android应用程序,该应用程序带有一个与服务器保持MQTT连接的服务。该服务从onstart命令返回一个*START\u STICKY*,以便Android在因资源短缺而终止服务时重新启动该服务。但问题是,这项服务经常被Android操作系统扼杀。它有时会在几秒钟内终止服务一次,即使设备上没有其他进程工作(内存为2GB)。为什么Android如此频繁地终止我的服务?如何减少重新启动的次数?我的服务应该被尽可能少地终止,因为它断开了我的tcp连接,客户端必须重新连接,这会在我们的
public class GTAndroidMQTTService extends Service implements MqttCallback {
private void init() {
this.clientId = Settings.System.getString(getContentResolver(), Secure.ANDROID_ID);
}
@Override
@Deprecated
public void onStart(Intent intent, int startId) {
logger("onStart() called");
super.onStart(intent, startId);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
logger("onStartCommand() called");
if (client == null) {
try {
init();
conOpt = new MqttConnectOptions();
conOpt.setCleanSession(false);
conOpt.setUserName("...");
conOpt.setPassword("...");
try {
char[] keystorePass = getString(R.string.keystorepass).toCharArray();
KeyStore keyStore = KeyStore.getInstance("BKS");
keyStore.load(getApplicationContext().getResources().openRawResource(R.raw.prdkey),
keystorePass);
TrustManagerFactory trustManagerFactory = TrustManagerFactory
.getInstance(KeyManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(keyStore);
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory
.getDefaultAlgorithm());
kmf.init(keyStore, keystorePass);
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(kmf.getKeyManagers(), trustManagerFactory.getTrustManagers(), null);
conOpt.setSocketFactory(sslContext.getSocketFactory());
} catch (Exception ea) {
}
client = new MqttClient(this.mqttURL, clientId, new MqttDefaultFilePersistence(folder));
client.setCallback(this);
conOpt.setKeepAliveInterval(this.keepAliveSeconds);
} catch (MqttException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if (intent == null) {
Log.i("TAG", "Android restarted the service[START_STICKY]");
if (client != null) {
tryToEstablishConnection();
}
}
return START_STICKY;
}
public void unsubscribe(String topicName) throws MqttException {
try {
client.unsubscribe(topicName);
} catch (Exception e) {
Log.i("TAG", "Unsubscribing from topic \"" + topicName + "has failed: " + e.toString());
}
}
private void retry() {
try {
notifyUserWithServiceStatus("Status Changed", "Status", "Connecting");
client.connect(conOpt);
notifyUserWithServiceStatus("Status Changed", "Status", "User Connected #" + (++retrycnt));
} catch (Exception e) {
notifyUserWithServiceStatus("Status Changed", "Status", "Cannot Connect");
e.printStackTrace();
}
}
public void subscribe(String topicName, int qos) throws MqttException {
try {
client.subscribe(topicName, qos);
} catch (Exception e) {
}
}
public void disconnect() {
try {
client.disconnect();
} catch (MqttException e) {
e.printStackTrace();
}
}
@Override
public IBinder onBind(Intent intent) {
logger("onBind() called");
return null;
}
@Override
public void onCreate() {
logger("onCreate() called");
super.onCreate();
}
@Override
public void connectionLost(Throwable arg0) { // Connection lost
notifyUserWithServiceStatus("Status Changed", "Status", "Connection Lost!");
tryToEstablishConnection();
}
private void tryToEstablishConnection() {
if (!retrying) {
retrying = true;
new Thread(new Runnable() {
@Override
public void run() {
for (;;) {
try {
if (isOnline() && !isConnected()) {
retry();
Thread.sleep(RETRY_INTERVAL);
} else if (isConnected()) {
retrying = false;
break;
} else if (!isOnline()) {
retrying = false;
break;
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}).start();
}
}
private class NetworkConnectionIntentReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context ctx, Intent intent) {
PowerManager pm = (PowerManager) getSystemService(POWER_SERVICE);
WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "MQTT");
wl.acquire();
if (isOnline() && !isConnected())
notifyUserWithServiceStatus("Status Changed", "Status", "Online but not connected");
else if (!isOnline())
notifyUserWithServiceStatus("Status Changed", "Status", "Connection Lost!");
tryToEstablishConnection();
wl.release();
}
}
private boolean isConnected() {
try {
return client.isConnected();
} catch (Exception e) {
return false;
}
}
private boolean isOnline() {
ConnectivityManager conMgr = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo i = conMgr.getActiveNetworkInfo();
if (i == null)
return false;
if (!i.isConnected())
return false;
if (!i.isAvailable())
return false;
return true;
}
@Override
public void onDestroy() {
logger("onDestroy() called");
try {
client.disconnect();
Log.i("TAG", "Service stopped");
} catch (MqttException e) {
e.printStackTrace();
}
super.onDestroy();
}
@Override
public void deliveryComplete(IMqttDeliveryToken arg0) {
// TODO Auto-generated method stub
}
}
听起来好像您的服务正在应用程序进程中运行;它与你的活动直接相关吗 您将希望以完全不同的流程运行它;您可以通过在清单中添加以下声明来完成此操作:
<service
android:name=".ServiceClassName"
android:process=":yourappname_background" >
然后对任何接收方声明使用相同的android:process属性。绑定到您的服务会使其保持活动状态吗?一些背景: 创建服务时,必须确保在后台线程中启动工作。IntentService在后台线程上运行,而服务在主线程上运行 默认情况下,服务在承载它的应用程序的主线程中运行 资料来源: 看看 阅读下面类似的问题 类似的答案如下: 该服务可以在没有UI的任务中使用,但不能太长。若需要执行长任务,则必须在服务中使用线程 我还建议阅读Commonware对 我的建议:
我会移动到一个智能服务或唤醒服务,并考虑用固定的间隔更新信息,而不是使用一个固定的TCP连接。基于HTTP的API可以通过SSL提供相同的信息。
您是否尝试在清单中添加android:process=“:different”?它可能因为您的活动被终止而被终止?我现在说不通!我认为即使活动被终止,后台服务也会继续运行。android:process=“:different”
到底做什么?在不同的进程上运行服务。不过,我还是很不确定。另一种防止系统杀死它(通常)的方法是使用startForeground
。检查,android.app.Notification)我试图将其作为前台服务,但我们不能接受通知中说“…正在运行”,我们无法阻止它出现在android 4.3设备上(例如Nexus)好的,请将android:process=“:different”
添加到清单中。例如
那么,Whatsapp和类似Whatsapp的应用程序如何处理此类情况呢?据我所知,他们使用了一个修改过的XMPP变体,它确实在下面建立了TCP连接。