后台服务在android中被杀死

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/12219249/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 10:03:16  来源:igfitidea点击:

Background Service getting killed in android

androidandroid-service

提问by Ashwin

We have developed an Android Application which involves a service in the background. To implement this background service we have used IntentService. We want the application to poll the server every 60 seconds. So in the IntentService, the server is polled in a while loop. At the end of the while loop we have used Thread.sleep(60000)so that the next iteration starts only after 60 seconds.
But in the Logcat, I see that sometimes it takes the application more than 5 minutes to wake up (come out of that sleep and start the next iteration). It is never 1 minuteas we want it to be.

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

What is the reason for this? Should background Services be implemented in a different way?

这是什么原因?后台服务是否应该以不同的方式实现?

Problem2

问题2

Android kills this background process (intent service) after sometime. Can't exactly say when. But sometimes its hours and sometimes days before the background service gets killed. I would appreciate it if you would tell me the reason for this. Because Services are not meant to be killed. They are meant to run in background as long as we want it to.

一段时间后,Android 会终止此后台进程(意图服务)。不能确切地说是什么时候。但有时它会在后台服务被杀死之前的几个小时甚至几天。如果你能告诉我这样做的原因,我将不胜感激。因为服务并不意味着被杀死。只要我们愿意,它们就可以在后台运行。

Code :

代码 :

@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;
    }
  }

}

But whenever the service is killed, it happens when the the process is asleep. The last log reads - Sleeping : Sleeping. Why does the service gets killed?

但是每当服务被终止时,它就会在进程休眠时发生。最后一个日志读取 - Sleeping : Sleeping。为什么服务会被杀死?

回答by AlexN

The main problem is that we cannot say

主要问题是我们不能说

Services are not meant to be killed. They are meant to run in background as long as we want it to.

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

Basically, that is not true. System still can terminate the service in low memory and possibly other situations. There are 2 ways to overcome this:

基本上,事实并非如此。系统仍然可以在内存不足和可能的其他情况下终止服务。有两种方法可以克服这个问题:

  1. If you are implementing the service, override onStartCommand()and return START_STICKYas the result. It will tell the system that even if it will want to kill your service due to low memory, it should re-create it as soon as memory will be back to normal.
  2. If you are not sure 1st approach will work - you'll have to use AlarmManager http://developer.android.com/reference/android/app/AlarmManager.html. That is a system service, which will execute actions when you'll tell, for example periodically. That will ensure that if your service will be terminated, or even the whole process will die(for example with force close) - it will be 100% restarted by AlarmManager.
  1. 如果您正在实施该服务,则覆盖onStartCommand()START_STICKY作为结果返回 。它会告诉系统即使由于内存不足而想要终止您的服务,它也应该在内存恢复正常后立即重新创建它。
  2. 如果您不确定第一种方法是否有效 - 您必须使用 AlarmManager http://developer.android.com/reference/android/app/AlarmManager.html。那是一个系统服务,它将在您告诉时执行操作,例如定期执行。这将确保如果您的服务将被终止,或者甚至整个过程都将终止(例如强制关闭) - 它将被 AlarmManager 100% 重新启动。

Good luck

祝你好运

回答by Alexander Kulyakhtin

You could use ScheduledExecutorServicedesigned specifically for such purpose.

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

Don't use Timers, as demonstrated in "Java Concurrency in Practice"they can be very inaccurate.

不要使用计时器,如“Java 并发实践”中所示,它们可能非常不准确。

回答by zapl

IntentServiceis not intended to keep running in a whileloop. The idea is to react to an Intent, do some processing and stop the service once done.

IntentService不打算保持while循环运行。这个想法是对 an 做出反应Intent,做一些处理并在完成后停止服务。

That does not mean that it's not working and I can't tell you why you see such long delays but the cleaner solution is to use some external source to poke the service periodically. Besides vanilla Java methods you can also have a look at the AlarmManageror a Handleras mentioned in the AlarmManagerdocumentation.

这并不意味着它不起作用,我不能告诉你为什么你看到这么长的延迟,但更干净的解决方案是使用一些外部资源定期戳服务。除了普通的 Java 方法,您还可以查看文档中提到的theAlarmManager或 a 。HandlerAlarmManager

The Handlerway would work like this

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);
    }
}

A simple Activity(which could be extended to have that functionality in all your activities) that sends itself a Messageall the time while it is running (here between onStartand onStop)

一个简单的Activity(可以扩展为在您的所有活动中具有该功能),Message它在运行时始终向自己发送一个(在onStart和之间onStop

回答by Finding Nemo 2 is happening.

A better solution would be have an AlarmManager go off every 60 seconds. This AlarmManager then starts the service that polls the server, the service then starts a new AlarmManager, its a recursive solution that works quite well.

更好的解决方案是让 AlarmManager 每 60 秒关闭一次。然后这个 AlarmManager 启动轮询服务器的服务,然后该服务启动一个新的 AlarmManager,它是一个运行良好的递归解决方案。

This solution will be more reliable as you dont have the threat of the Android OS killing your service, looming over you. As per API: The Alarm Manager is intended for cases where you want to have your application code run at a specific time, even if your application is not currently running.

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

In your UI/main activity etc, set this timer, to go off in 60 seconds:

在您的 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

In yourservice.classyou could have this, it checks the connection state, if its good it sets the timer to go off in another 60 seconds:

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
                               }
                }
}

回答by plaisthos

Services get killed. Like app gets killed. It is Android philosophy that you can get killed at any time.

服务被杀死。就像应用程序被杀死一样。你可以随时被杀死是安卓的哲学。

You should as other wrote not make the assumption that your backgroundservice runs forever.

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

But you can use a foreground serviceto drastically reduce the chance of getting killed/restarted. Note that this forces a notification which is always visible. For example music players, vpn applications and sportstracker use this API.

但是您可以使用前台服务来大大减少被杀死/重新启动的机会。请注意,这会强制通知始终可见。例如音乐播放器、vpn 应用程序和sportstracker 使用此API。

回答by Rafael

For Problem 1, from vanilla Java, Thread.Sleep()is guaranted to wake the thread after the timer has expired, but not exactly after it has expired, it may be later depending mainly of the statuses of other threads, priority, etc.; so if you sleep your thread one second, then it will sleep at least a second, but it may be 10 depending of a lot of factors, i'm not very versed in Android development, but i'm pretty sure it's the same situation.

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

For Problem 2, services can be killed when memory get low or manually by the user, so as others have pointed probably using AlarmManager to restart your service after a certain time will help you to have it running all the time.

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

回答by benkdev

Android is pretty good about killing off long running services. I have found CommonsWare's WakefulIntentService useful in my application: https://github.com/commonsguy/cwac-wakeful

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

It allows you to specify a time interval as you are trying to do by sleeping.

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

回答by abhi.nalavade

You can try Jobscheduler implementation with JobService running in Background, which is recommended above Android O.

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

回答by Sahil Mahajan Mj

It could be probably for two reasons..
  1. Either the while loop is creating an issue, it is making the handler to work until temp==true
  2. Adding to it is threads, that is creating long delaysupto 6 seconds. In case, the system is working for a large database, creating long delaysbetween each query will add on the system memory. When the memory usage for application become so huge that the system memory gets low, system has to terminate the process..

    Solution for the Problem..

  3. You could replace above with Alarm Managerto revoke system services after a particular interval of time using Alarm Manager.

  4. Also for getting intent back after the system recovers the application from termination, you should use START_REDELIVER_INTENT. It is to get your last working intent back after the application terminates. for its usage, study https://developer.android.com/reference/android/app/Service.html#START_REDELIVER_INTENT
  1. 要么 while 循环正在创建一个问题,它使处理程序工作,直到 temp==true
  2. 添加到它的是线程,即创建long delaysupto 6 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

回答by JustinMorris

Sound like you should be using a Serviceinstead of an IntentServicebut if you want to use an IntentServiceand have it run every 60 seconds you should use the AlarmManagerinstead of just telling the Threadto sleep.. IntentServices want to stop, let it and have AlarmManagerwake it up when it should run again.

听起来像是你应该使用一个Service替代的IntentService,但如果你想使用IntentService,并让它运行每隔60秒,你应该使用AlarmManager,而不是仅仅告诉Thread睡觉..IntentService小号想停止,让它和具有AlarmManager唤醒它时它应该再次运行。