Android非常频繁地杀死该服务

时间:2013-10-07 11:45:47

标签: android tcp android-service mqtt

我们准备了一个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
    }
}

3 个答案:

答案 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提供相同的信息。