2013-10-07 3 views
3

Мы подготовили приложение для Android с сервисом, поддерживающим MQTT-соединение с нашим сервером. Служба возвращает * START_STICKY * из своего onStartCommand, чтобы Android перезапустил службу на случай, если она убьет службу для нехватки ресурсов. Но проблема в том, что служба очень часто убивается ОС Android. Он иногда убивает услугу раз в несколько секунд, даже если на устройстве нет другого процесса (с 2 ГБ оперативной памяти). Почему Android так часто убивает мой сервис? Как уменьшить количество перезапусков? Моя служба должна быть убита как можно меньше, поскольку она отключает мое соединение tcp, и клиент должен снова подключиться, что вызывает большую нагрузку на наш сервер. Что может быть неправильным с этим кодом? ThanksAndroid очень часто убивает службу

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

Вы пытались добавить манифест 'android: process =": ​​different "'? Это может быть убито, потому что ваша деятельность убита? Я не имею смысла прямо сейчас! –

+0

Я думаю, что фоновое обслуживание поддерживается, даже если активность убита. Что делает 'android: process =": ​​different "' точно? – Alpay

+0

Запускает службу в другом процессе. Тем не менее, я очень не уверен. Другим способом предотвращения системы от ее убийства (часто) является использование 'startForeground'. Проверьте http://developer.android.com/reference/android/app/Service.html#startForeground(int, android.app.Notification) –

ответ

0

Звучит так, как будто ваша служба работает в процессе Application; это напрямую связано с вашей деятельностью?

Вы хотите запустить его совсем другим способом; Вы можете сделать это, добавив следующее заявление в манифесте:

<service 
    android:name=".ServiceClassName" 
    android:process=":yourappname_background" > 

И затем использовать тот же андроид: атрибут процесса для любых деклараций приемника, а также.

0

Связано ли с вашим сервисом его сохранение?

0

Некоторые фона:

При создании сервиса вы должны убедиться, что ваша работа начинается в фоновом потоке. IntentService работает в фоновом потоке, пока служба работает в основном потоке.

Служба работает в основном потоке приложения, которое его, по умолчанию

Источник: http://developer.android.com/guide/components/services.html

Взгляните на http://developer.android.com/guide/components/services.html#ExtendingIntentService

Читать ниже аналогичных вопросов.

Подобный ответ на: Service vs IntentService

Сервис может быть использован в задачах, не имеющих пользовательского интерфейса, но не должно быть слишком длинным. Если вам нужно выполнять длительные задачи, вы должны использовать потоки в службе.

Также я предлагаю прочитать ответ CommonsWare на How to always run a service in the background?

Мое предложение:

Я хотел бы перейти к IntentService или WakefulIntentService и рассмотреть вопрос об обновлении информации с фиксированным интервалом вместо использования постоянного TCP подключение. API, основанный на HTTP, может предоставлять такую ​​же информацию через SSL.

+0

Итак, как Whatsapp и Whatsapp как приложения обрабатывают такие ситуации? Насколько я знаю, они используют модифицированный вариант XMPP, и он действительно устанавливает TCP-соединение ниже. – Alpay

Смежные вопросы