Подтвердить что ты не робот

Фоновая служба убивается в андроиде

Мы разработали приложение для Android, которое включает сервис в фоновом режиме. Для реализации этой фоновой службы мы использовали IntentService. Мы хотим, чтобы приложение опросило сервер каждые 60 seconds. Таким образом, в IntentService сервер опрошен в цикле while. В конце цикла while мы использовали Thread.sleep(60000), так что следующая итерация начинается только через 60 секунд.
Но в Logcat я вижу, что иногда требуется приложение более 5 минут, чтобы проснуться ( выйти из этого сна и начать следующую итерацию). Это никогда не 1 minute, как мы хотим.

В чем причина этого? Если фоновые службы будут реализованы по-другому?

задачи2

Android иногда убивает этот фоновый процесс (услуга намерения). Не могу точно сказать, когда. Но иногда его часы, а иногда и дни до того, как фоновая служба убита. Буду признателен, если вы скажете мне причину этого. Потому что Службы не предназначены для убийства. Они предназначены для работы в фоновом режиме, пока мы этого хотим.

Код:

@Override
 protected void onHandleIntent(Intent intent) {
  boolean temp=true;
  while(temp==true) {
    try {
      //connect to the server 
      //get the data and store it in the sqlite data base
    }
    catch(Exception e) {
      Log.v("Exception", "in while loop : "+e.toString());
    }
    //Sleep for 60 seconds
    Log.v("Sleeping", "Sleeping");
    Thread.sleep(60000);
    Log.v("Woke up", "Woke up");

    //After this a value is extracted from a table
    final Cursor cur=db.query("run_in_bg", null, null, null, null, null, null);
    cur.moveToLast();
    String present_value=cur.getString(0);
    if(present_value==null) {
       //Do nothing, let the while loop continue  
    }
    else if( present_value.equals("false") || present_value.equals("False") ) {
       //break out of the while loop
       db.close();
       temp=false;
       Log.v("run_in_bg", "false");
       Log.v("run_in_bg", "exiting while loop");
       break;
    }
  }

}

Но всякий раз, когда служба убивается, это происходит, когда процесс засыпает. Последний журнал читает - Sleeping : Sleeping. Почему служба убивается?

4b9b3361

Ответ 1

Основная проблема заключается в том, что мы не можем сказать

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

В принципе, это не так. Система по-прежнему может прекратить обслуживание в условиях низкой памяти и, возможно, в других ситуациях. Есть два способа преодолеть это:

  • Если вы реализуете службу, переопределите onStartCommand() и верните START_STICKY в качестве результата. Он сообщит системе, что даже если она захочет убить вашу службу из-за низкой памяти, она должна воссоздать ее, как только память вернется к нормальной работе.
  • Если вы не уверены, что первый подход будет работать, вам придется использовать AlarmManager http://developer.android.com/reference/android/app/AlarmManager.html. Это системная служба, которая будет выполнять действия, когда вы скажете, например, периодически. Это гарантирует, что если ваша служба будет прекращена или даже весь процесс умрет (например, с силой закрыть) - он будет перезапущен на 100% AlarmManager.

Удачи.

Ответ 3

IntentService не предназначен для работы в цикле while. Идея состоит в том, чтобы отреагировать на Intent, выполнить некоторую обработку и остановить службу после ее выполнения.

Это не значит, что он не работает, и я не могу сказать вам, почему вы видите такие длительные задержки, но более чистым решением является использование некоторого внешнего источника для периодического вызова службы. Помимо ванильных Java-методов вы также можете посмотреть AlarmManager или Handler, как указано в документации AlarmManager.

Handler будет работать следующим образом

public class TriggerActivity extends Activity implements Handler.Callback {
    // repeat task every 60 seconds
    private static final long REPEAT_TIME = 60 * 1000;
    // define a message id
    private static final int MSG_REPEAT = 42;

    private Handler mHandler;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mHandler = new Handler(this);
    }

    @Override
    protected void onStart() {
        super.onStart();
        // start cycle immediately
        mHandler.sendEmptyMessage(MSG_REPEAT);
    }

    @Override
    protected void onStop() {
        super.onStop();
        // stop cycle
        mHandler.removeMessages(MSG_REPEAT);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mHandler = null;
    }

    @Override
    public boolean handleMessage(Message msg) {
        // enqueue next cycle
        mHandler.sendEmptyMessageDelayed(MSG_REPEAT, REPEAT_TIME);
        // then trigger something
        triggerAction();
        return true;
    }

    private void triggerAction() {
        // trigger the service
        Intent serviceIntent = new Intent(this, MyService.class);
        serviceIntent.setAction("com.test.intent.OPTIONAL_ACTION");
        startService(serviceIntent);
    }
}

Простой Activity (который может быть расширен, чтобы иметь эту функциональность во всех ваших действиях), который отправляет себя Message все время, пока он работает (здесь между onStart и onStop)

Ответ 4

Лучшим решением будет иметь AlarmManager каждые 60 секунд. Затем AlarmManager запускает службу, которая опросает сервер, затем служба запускает новый AlarmManager, это рекурсивное решение, которое работает достаточно хорошо.

Это решение будет более надежным, так как у вас нет угрозы для ОС Android, убивающей ваш сервис, нависший над вами. В соответствии с API: диспетчер Alarm Manager предназначен для случаев, когда вы хотите, чтобы ваш код приложения выполнялся в определенное время, даже если ваше приложение в настоящее время не работает.

В вашем пользовательском интерфейсе/основной деятельности и т.д. установите этот таймер, чтобы выйти за 60 секунд:

long ct = System.currentTimeMillis(); //get current time
AlarmManager mgr=(AlarmManager)getApplicationContext().getSystemService(Context.ALARM_SERVICE);
Intent i= new Intent(getApplicationContext(), yourservice.class);
PendingIntent pi=PendingIntent.getService(getApplicationContext(), 0, i, 0);

   mgr.set(AlarmManager.RTC_WAKEUP, ct + 60000 , pi); //60 seconds is 60000 milliseconds

В yourservice.class вы можете получить это, он проверяет состояние соединения, если он хорош, он выключает таймер еще через 60 секунд:

    public class yourservice extends IntentService {

                    public yourservice() { //needs this constructor
                        super("server checker");
                    }

                    @Override
                    protected void onHandleIntent(Intent intent) {
                        WifiManager wificheck = (WifiManager) this.getSystemService(Context.WIFI_SERVICE);

                        if(check for a certain condition your app needs etc){
            //could check connection state here and stop if needed etc
                              stopSelf(); //stop service
                        }
                           else{ //poll the server again in 60 seconds
            long ct = System.currentTimeMillis();
            AlarmManager mgr=(AlarmManager)getApplicationContext().getSystemService(Context.ALARM_SERVICE);
            Intent i= new Intent(getApplicationContext(), yourservice.class);
            PendingIntent pi=PendingIntent.getService(getApplicationContext(), 0, i, 0);

           mgr.set(AlarmManager.RTC_WAKEUP, ct + 60000 , pi); 
           stopSelf(); //stop service since its no longer needed and new alarm is set
                               }
                }
}

Ответ 5

Службы убиты. Как приложение убивается. Это философия Android, которую можно убить в любое время.

Вы должны, как и другие, не делать предположение, что ваш фоновый сервис работает навсегда.

Но вы можете использовать базовую услугу fora , чтобы резко уменьшить вероятность того, что вас убили/перезапустили. Обратите внимание, что это вызывает уведомление, которое всегда видно. Например, музыкальные проигрыватели, приложения vpn и sportstracker используют этот API.

Ответ 6

Для проблемы 1, с ванильной Java, Thread.Sleep() гарантируется пробуждение потока после истечения таймера, но не сразу после его истечения, оно может быть позже зависит в основном от статусов других потоков, приоритета и т.д.. так что если вы спите свою нить на одну секунду, тогда она будет спать хотя бы на секунду, но может быть 10 в зависимости от множества факторов, я не очень разбираюсь в разработке Android, но я уверен, что в той же ситуации.

Для проблемы 2 службы могут быть убиты, когда память становится низкой или вручную пользователем, так как другие указали, вероятно, использовать AlarmManager для перезапуска вашего сервиса через определенное время, чтобы помочь вам запустить его все время.

Ответ 7

Похоже, вы должны использовать Service вместо IntentService, но если вы хотите использовать IntentService и запускать его каждые 60 секунд, вы должны использовать AlarmManager вместо того, чтобы просто указывать Thread спать.. IntentService хотите остановиться, пусть он и AlarmManager разбудит его, когда он снова запустится.

Ответ 8

It could be probably for two reasons..
  • Либо цикл while создает проблему, он делает обработчик работать до temp==true
  • Добавление к нему потоков, создающих long delays upto 6 seconds. В случае, если система работает для большой базы данных, создание long delays между каждым запросом будет добавляться в системную память. Когда использование памяти для приложения становится настолько огромным, что system memory gets low, система должна terminate the process..

    Решение задачи.

  • Вы можете заменить выше Alarm Manager, чтобы отменить системные службы через определенный промежуток времени с помощью диспетчера аварийных сигналов.

  • Также, чтобы получить намерение вернуться после того, как система восстановит приложение от завершения, вы должны использовать START_REDELIVER_INTENT. Он должен вернуть ваше последнее рабочее намерение после завершения работы приложения. для его использования, изучите https://developer.android.com/reference/android/app/Service.html#START_REDELIVER_INTENT

Ответ 9

Android очень хорош в том, чтобы убивать долгосрочные сервисы. Я нашел CommonsWare WakefulIntentService полезным в своем приложении: https://github.com/commonsguy/cwac-wakeful

Это позволяет вам указать временной интервал, который вы пытаетесь сделать, спя.

Ответ 10

Вы можете попробовать реализацию Jobscheduler с JobService, работающим в фоновом режиме, что рекомендуется выше Android O.