后台服务在android中被杀死

时间:2012-08-31 16:28:16

标签: android android-service

我们开发了一个Android应用程序,它涉及后台服务。为了实现此后台服务,我们使用了IntentService。我们希望应用程序每60 seconds轮询一次服务器。所以在IntentService中,服务器在while循环中轮询。在while循环结束时,我们使用了Thread.sleep(60000),以便下一次迭代仅在60秒后开始。
但在Logcat中,我看到有时需要应用程序超过5几分钟醒来(从睡眠中走出来并开始下一次迭代)。它永远不会像我们希望的那样1 minute

这是什么原因?背景服务应该以不同的方式实施吗?

Problem2

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。为什么服务会被杀死?

10 个答案:

答案 0 :(得分:78)

主要问题是我们不能说

  

服务并不意味着被杀死。只要我们想要它们,它们就意味着在后台运行。

基本上,这不是真的。系统仍然可以在低内存和其他情况下终止服务。 有两种方法可以解决这个问题:

  1. 如果您要实施该服务,请覆盖onStartCommand()并返回START_STICKY作为结果。它会告诉系统即使它因内存不足而想要终止服务,只要内存恢复正常就应该重新创建它。
  2. 如果您不确定第一种方法是否有效 - 您将不得不使用AlarmManager http://developer.android.com/reference/android/app/AlarmManager.html。这是一个系统服务,它会在您告诉时执行操作,例如定期执行。这将确保如果您的服务将被终止,或者甚至整个过程将终止(例如强制关闭) - 它将由AlarmManager 100%重新启动。
  3. 祝你好运

答案 1 :(得分:6)

您可以使用专为此目的而设计的ScheduledExecutorService

不要使用定时器,如"Java Concurrency in Practice"中所示,它们可能非常不准确。

答案 2 :(得分:5)

IntentService无意继续在while循环中运行。我们的想法是对Intent做出反应,做一些处理并在完成后停止服务。

这并不意味着它不起作用,我不能告诉你为什么你会看到如此长的延迟,但更清晰的解决方案是使用一些外部来源定期戳服务。除了vanilla Java方法,您还可以查看Handler文档中提到的AlarmManagerAlarmManager

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之间{1}})

答案 3 :(得分:4)

更好的解决方案是让AlarmManager每60秒关闭一次。然后,此AlarmManager启动轮询服务器的服务,然后该服务启动一个新的AlarmManager,它是一个非常有效的递归解决方案。

此解决方案将更加可靠,因为您没有Android操作系统的威胁会导致您的服务中断,迫在眉睫。根据API:警报管理器适用于您希望在特定时间运行应用程序代码的情况,即使您的应用程序当前未运行。

在您的UI /主要活动等中,设置此计时器,在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
                               }
                }
}

答案 4 :(得分:2)

服务被杀死。就像app被杀了一样。 Android哲学可以随时杀死。

你应该像其他人所写的那样假设你的背景服务永远运行。

但你可以使用前ground service来大幅降低被杀/重启的可能性。请注意,这会强制始终可见的通知。例如音乐播放器,vpn应用程序和sportstracker使用此API。

答案 5 :(得分:1)

对于问题1,来自vanilla Java,Thread.Sleep()可以保证在计时器到期后唤醒线程,但不完全在它到期后,它可能稍后主要取决于其他线程的状态,优先级等等;所以,如果你让你的线程休息一秒钟,那么它至少会睡一秒钟,但是根据很多因素它可能是10,我对Android开发并不是很精通,但我很确定这是相同的情况

对于问题2,服务可以在内存变低或用户手动时被杀死,因此其他人指出可能使用AlarmManager在一段时间后重新启动服务将帮助您让它一直运行。

答案 6 :(得分:0)

听起来你应该使用Service代替IntentService但是如果你想使用IntentService并让它每60秒运行一次,你应该使用AlarmManager而不只是告诉Thread要睡觉.. IntentService想要停止,让它在AlarmManager再次运行时将其唤醒。

答案 7 :(得分:0)

It could be probably for two reasons..
  1. while循环正在创建一个问题,它使处理程序工作到temp==true
  2. 添加它是线程,即创建long delays6 seconds。 如果系统正在为大型数据库工作,则在每个查询之间创建long delays将添加到系统内存中。 当应用程序的内存使用量变得如此之大以至于system memory gets low,系统必须terminate the process ..

    解决问题..

  3. 您可以使用警报管理器在特定时间间隔后用Alarm Manager替换以撤消系统服务。

  4. 此外,为了在系统从终止恢复应用程序后获取意图,您应该使用START_REDELIVER_INTENT。在应用程序终止后,它将恢复您的上一次工作意图。对于它的用法,研究https://developer.android.com/reference/android/app/Service.html#START_REDELIVER_INTENT

答案 8 :(得分:0)

Android非常适合杀掉长期运行的服务。我发现CommonsWare的WakefulIntentService在我的应用程序中很有用:https://github.com/commonsguy/cwac-wakeful

它允许您通过睡眠来指定时间间隔。

答案 9 :(得分:0)

您可以尝试在后台运行JobService的Jobscheduler实现,建议在Android O之上运行。