后台服务在android中被杀死

Posted

技术标签:

【中文标题】后台服务在android中被杀死【英文标题】:Background Service getting killed in android 【发布时间】:2012-08-26 12:02:58 【问题描述】:

我们开发了一个 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。为什么服务会被杀死?

【问题讨论】:

您应该改用Timer 并以固定速率安排它,而不是在while 循环中使用Thread.sleep() 因为它们允许您完全按照自己的意愿去做 - 以一定的时间间隔重复一项任务。不一定是您问题的答案,而是一个建议(因此我要发表评论,而不是答案)。也总是有可能使用 Thread.sleep() 是它需要 5 分钟的原因 - 也许 Timer 可能做不到?我觉得值得一试。 @Ashwin:如果你能分享这个问题的解决方案,那就太好了。我一直面临一个这样的问题,但是,这里建议的解决方案似乎都没有奏效。 @User11012 : 你的问题到底是什么? @Ashwin:我需要每分钟执行一个函数。此功能正在从应用程序向服务器发出 POST 调用,并每分钟传输用户的位置。位置坐标会传输几个小时,但是,几个小时后,位置坐标到服务器的传输会自行停止。代码已在此链接共享:***.com/questions/30334215/… 【参考方案1】:

主要问题是我们不能说

服务不应该被杀死。只要我们愿意,它们就可以在后台运行。

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

    如果您正在实施服务,请覆盖onStartCommand() 并返回START_STICKY 作为结果。它会告诉系统,即使由于内存不足而想终止您的服务,它也应该在内存恢复正常后立即重新创建它。 如果您不确定第一种方法是否有效 - 您必须使用 AlarmManager http://developer.android.com/reference/android/app/AlarmManager.html 。那是一个系统服务,它会在您告知时执行操作,例如定期执行。这将确保如果您的服务将被终止,甚至整个进程都会终止(例如强制关闭) - 它将被 AlarmManager 100% 重新启动。

祝你好运

【讨论】:

如果情况并非总是如此,那么音乐播放器、雅虎邮箱、Facebook 等的后台服务呢?他们永远不会被杀死。 请检查此方法 - developer.android.com/reference/android/app/… 如前所述,运行主要用户功能(如音乐播放)的繁重服务 - 可以 startForeground() - 系统将尽量不停止它。但是您需要提供通知以向用户显示后台服务正在运行。此外,仍然不能保证系统不会停止它,但可能性要小得多。 如果我没记错的话,如果任何进程被强制关闭,AlarmManager 将不会再次启动它。 关于睡眠时间超过 60 秒的问题 - 这可能是因为手机进入睡眠状态并且 Thread.sleep() 的计时器也进入睡眠状态(参见 SystemClock.uptimeMillis())。在这种情况下,防止手机休眠可以解决,但最好使用 AlarmManager 或者推送消息 你是说后台服务作为音乐播放器可以被安卓“暂停”吗?【参考方案2】:

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

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

【讨论】:

+1 表示“不要使用计时器”。我不知道这个不准确的问题,现在正在研究:)。 所以你建议每隔几分钟使用ScheduledExecutorService绑定到服务,如果失败,它会重新启动? 看来使用onTaskRemoved() 的重新启动方法很容易——无论是Alarm Manager 还是ScheduledExecutorService【参考方案3】:

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

这并不意味着它不起作用,我无法告诉您为什么会看到如此长的延迟,但更简洁的解决方案是使用一些外部资源来定期戳服务。除了普通的 Java 方法,您还可以查看 AlarmManagerHandler,如 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(在onStartonStop之间)

【讨论】:

请在我的问题中查看问题 2。该服务正在被终止。 嘿,我正在尝试您的警报管理器解决方案,但该服务正在死去。如果您能回答我的问题,我将不胜感激***.com/questions/51460417/…【参考方案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
                               
                

【讨论】:

我在使用警报管理器时遇到了一些问题。请看我的问题 - ***.com/questions/12256434/… 嘿,我正在尝试您的警报管理器解决方案,但该服务正在死去。如果您能回答我的问题***.com/questions/51460417/…,我将不胜感激【参考方案5】:

服务被杀死。就像应用程序被杀死一样。 Android 的哲学就是你随时都可能被杀。

您不应该像其他人写的那样假设您的后台服务永远运行。

但是您可以使用 foreground service 来大幅降低被杀死/重新启动的机会。请注意,这会强制发出始终可见的通知。例如音乐播放器、*** 应用程序和 sportstracker 使用此 API。

【讨论】:

嘿,我正在尝试使用前台服务,但它仍然死机。如果您能回答我的问题,我将不胜感激***.com/questions/51460417/…【参考方案6】:

对于问题 1,从 vanilla Java 中,Thread.Sleep() 保证在计时器到期后唤醒线程,但不是恰好在它到期之后,它可能会更晚,主要取决于其他线程的状态、优先级等.;所以如果你让你的线程休眠一秒钟,那么它至少会休眠一秒钟,但它可能是 10 取决于很多因素,我不太精通 Android 开发,但我很确定这是同样的情况.

对于问题 2,服务可以在内存不足时终止或由用户手动终止,因此正如其他人所指出的那样,可能使用 AlarmManager 在一段时间后重新启动您的服务将帮助您让它一直运行。

【讨论】:

如果服务可以被杀死,那么音乐播放器、雅虎邮箱、Facebook 等的后台服务呢?它们永远不会被杀死。 音乐播放器在运行时不会闲置,因此它们不会被自动杀死(您需要手动执行),邮件和 Facebook 应用程序在被手动或自动杀死时会自行生成。 【参考方案7】:

听起来您应该使用Service 而不是IntentService,但如果您想使用IntentService 并让它每60 秒运行一次,您应该使用AlarmManager 而不是仅仅告诉@987654326 @ 睡觉.. IntentServices 想要停止,让它在它应该再次运行时让 AlarmManager 唤醒它。

【讨论】:

请查看编辑。如果我们使用Service而不是IntentService,这些问题会得到解决吗? 嘿,我正在尝试您的警报管理器解决方案,但该服务正在死去。如果您能回答我的问题,我将不胜感激***.com/questions/51460417/…【参考方案8】:

Android 非常擅长终止长时间运行的服务。我发现 CommonsWare 的 WakefulIntentService 在我的应用程序中很有用:https://github.com/commonsguy/cwac-wakeful

它允许你指定一个时间间隔,就像你试图通过睡眠来做的那样。

【讨论】:

【参考方案9】:
It could be probably for two reasons..
    while 循环会产生问题,它使处理程序一直工作到temp==true

    添加到它的是线程,即创建long delays6 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

【讨论】:

【参考方案10】:

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

【讨论】:

以上是关于后台服务在android中被杀死的主要内容,如果未能解决你的问题,请参考以下文章

当应用程序从堆栈中被杀死时,后台服务停止

应用程序被杀死时Android后台服务正在重新启动

Android 关于后台杀死App之后改变服务器状态的一些尝试

我想在杀死进程后保持活动后台服务

当应用程序在颤动中被杀死/终止时,从后台事件启动应用程序

即使应用程序在 ios 中被杀死或从后台删除,如何继续更新我的位置?