后台服务在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 方法,您还可以查看 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
之间)
【讨论】:
请在我的问题中查看问题 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 @ 睡觉.. IntentService
s 想要停止,让它在它应该再次运行时让 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 delays
到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
【讨论】:
【参考方案10】:您可以尝试在后台运行 JobService 的 Jobscheduler 实现,在 Android O 以上推荐。
【讨论】:
以上是关于后台服务在android中被杀死的主要内容,如果未能解决你的问题,请参考以下文章