我们准备了一个Android应用程序,其服务与我们的服务器保持 MQTT连接。该服务从其onStartCommand返回* START_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
}
}
答案 0 :(得分:0)
听起来好像您的服务正在申请流程中运行;它与您的活动直接相关吗?
你想要完全运行它一个不同的过程;您可以通过在清单中添加以下声明来完成此操作:
<service
android:name=".ServiceClassName"
android:process=":yourappname_background" >
然后对任何接收者声明使用相同的android:process属性。
答案 1 :(得分:0)
绑定到您的服务是否可以保持活动?
答案 2 :(得分:0)
一些背景:
创建服务时,您必须确保您的工作是在后台线程中启动的。当服务在主线程上运行时,IntentService在后台线程上运行。
默认情况下,服务在托管它的应用程序的主线程中运行
来源:http://developer.android.com/guide/components/services.html
查看http://developer.android.com/guide/components/services.html#ExtendingIntentService
请阅读下面的类似问题。
类似的答案:Service vs IntentService
该服务可用于没有UI的任务,但不应太长。如果需要执行长任务,则必须使用Service中的线程。
另外我建议阅读CommonsWare对How to always run a service in the background?
的回答我的建议:
我将转移到IntentService或WakefulIntentService并考虑使用固定间隔更新信息,而不是使用常量tcp连接。基于HTTP的API可以通过SSL提供相同的信息。