Android频繁地终止服务

Android频繁地终止服务,android,tcp,android-service,mqtt,Android,Tcp,Android Service,Mqtt,我们准备了一个Android应用程序,该应用程序带有一个与服务器保持MQTT连接的服务。该服务从onstart命令返回一个*START\u STICKY*,以便Android在因资源短缺而终止服务时重新启动该服务。但问题是,这项服务经常被Android操作系统扼杀。它有时会在几秒钟内终止服务一次,即使设备上没有其他进程工作(内存为2GB)。为什么Android如此频繁地终止我的服务?如何减少重新启动的次数?我的服务应该被尽可能少地终止,因为它断开了我的tcp连接,客户端必须重新连接,这会在我们的

我们准备了一个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连接。