我的应用程序使用了一种模式,我使用 Context#startService() 启动服务以及使用 Context#bindService() 绑定(bind)到它.这样我就可以独立于当前是否有任何客户端绑定(bind)到它来控制服务的生命周期。但是,我最近注意到,每当我的应用程序被系统杀死时,它很快就会重新启动所有正在运行的服务。此时将永远不会告诉服务停止,这会在发生时导调用池耗尽。这是一个最小的例子:
我发现有人遇到类似问题 here ,但从未被诊断或解决。
服务:
@Override
public void onCreate() {
Toast.makeText(this, "onCreate", Toast.LENGTH_LONG).show();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_NOT_STICKY;
}
@Override
public IBinder onBind(Intent intent) {
return new Binder();
}
Activity :
@Override
protected void onStart() {
super.onStart();
Intent service = new Intent(this, BoundService.class);
startService(service);
bindService(service, mServiceConnection, 0);
}
@Override
protected void onStop() {
unbindService(mServiceConnection);
Toast.makeText(this, "unbindService", Toast.LENGTH_SHORT).show();
super.onStop();
}
为了测试它,我启动了应用程序,它启动了服务并绑定(bind)到它。然后我退出了应用程序,该应用程序解除绑定(bind)(但使服务保持运行)。然后我做了
$ adb shell am kill com.tavianator.servicerestart
果然,5 秒后,“onCreate”toast 出现,表示服务再次启动。 Logcat 显示:
$ adb logcat | grep BoundService
W/ActivityManager( 306): Scheduling restart of crashed service com.tavianator.servicerestart/.BoundService in 5000ms
I/ActivityManager( 306): Start proc com.tavianator.servicerestart for service com.tavianator.servicerestart/.BoundService: pid=20900 uid=10096 gids={1028}
如果我用 BIND_AUTO_CREATE 替换 startService() 模式,问题就不会发生(即使我在应用程序仍然绑定(bind)到服务时崩溃)。如果我从不绑定(bind)到服务,它也可以工作。但是 start、bind 和 unbind 的组合似乎永远不会让我的服务死掉。
在杀死应用程序之前使用 dumpsys 会显示:
$ adb shell dumpsys activity services com.tavianator.servicerestart
ACTIVITY MANAGER SERVICES (dumpsys activity services)
Active services:
* ServiceRecord{43099410 com.tavianator.servicerestart/.BoundService}
intent={cmp=com.tavianator.servicerestart/.BoundService}
packageName=com.tavianator.servicerestart
processName=com.tavianator.servicerestart
baseDir=/data/app/com.tavianator.servicerestart-2.apk
dataDir=/data/data/com.tavianator.servicerestart
app=ProcessRecord{424fb5c8 20473:com.tavianator.servicerestart/u0a96}
createTime=-20s825ms lastActivity=-20s825ms
executingStart=-5s0ms restartTime=-20s825ms
startRequested=true stopIfKilled=true callStart=true lastStartId=1
Bindings:
* IntentBindRecord{42e5e7c0}:
intent={cmp=com.tavianator.servicerestart/.BoundService}
binder=android.os.BinderProxy@42aee778
requested=true received=true hasBound=false doRebind=false
最佳答案
看看这个document部分:服务生命周期变化(从 1.6 开始)
更新
经过一些调查(已创建项目,逐步运行描述的命令等) 我发现代码的工作方式与“服务生命周期更改”中描述的完全一样
我发现了什么:
adb shell am kill com.tavianator.servicerestart杀死什么都没有
(尝试adb shell,然后在shell中am kill com.tavianator.servicerestart
您将面临错误消息Error: Unknown command: kill)
所以,
运行您的应用程序,
运行adb shell
在shell中运行ps命令
查找您的应用的PID号
在shell运行命令kill <app_xx_PID>
你的PID号在哪里
重复杀死服务的步骤(如果它在自己的进程中运行)
检查服务是否正在运行(不应该),5-7秒后重新启动
更新
一种解决方案(不够好,但在某些情况下可用)是stopSelf()例如:
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Toast.makeText(this, "onStartCommand", Toast.LENGTH_LONG).show();
stopSelf();
return START_NOT_STICKY;
}
更新
更新的解决方案
void writeState(int state) {
Editor editor = getSharedPreferences("serviceStart", MODE_MULTI_PROCESS)
.edit();
editor.clear();
editor.putInt("normalStart", state);
editor.commit();
}
int getState() {
return getApplicationContext().getSharedPreferences("serviceStart",
MODE_MULTI_PROCESS).getInt("normalStart", 1);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (getState() == 0) {
writeState(1);
stopSelf();
} else {
writeState(0);
Toast.makeText(this, "onStartCommand", Toast.LENGTH_LONG).show();
}
return START_NOT_STICKY;
}
为什么进程被杀死时服务会重新启动?
据此document :
When a service is started, it has a lifecycle that's independent of the component that started it and the service can run in the background indefinitely, even if the component that started it is destroyed. As such, the service should stop itself when its job is done by calling stopSelf(), or another component can stop it by calling stopService().
Caution: It's important that your application stops its services when it's done working, to avoid wasting system resources and consuming battery power. If necessary, other components can stop the service by calling stopService(). Even if you enable binding for the service, you must always stop the service yourself if it ever received a call to onStartCommand()
从另一手文件说:
*START_NOT_STICKY* - If the system kills the service after onStartCommand() returns, do not recreate the service, unless there are pending intents to deliver. This is the safest option to avoid running your service when not necessary and when your application can simply restart any unfinished jobs.
因此,在阅读本文档和一些实验后,我认为系统将手动终止的服务视为未完成(崩溃:@see W/ActivityManager(306): Scheduling restart of crashed service)并重新启动它,尽管 onStartCommand 返回了值。
stopSelf() 或 stopService() - 不重启,如果工作完成了,为什么不呢?
关于android - 即使我使用了 START_NOT_STICKY,为什么当进程被终止时我的 Android 服务会重新启动?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12648447/
类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc
我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co
我正在使用的第三方API的文档状态:"[O]urAPIonlyacceptspaddedBase64encodedstrings."什么是“填充的Base64编码字符串”以及如何在Ruby中生成它们。下面的代码是我第一次尝试创建转换为Base64的JSON格式数据。xa=Base64.encode64(a.to_json) 最佳答案 他们说的padding其实就是Base64本身的一部分。它是末尾的“=”和“==”。Base64将3个字节的数据包编码为4个编码字符。所以如果你的输入数据有长度n和n%3=1=>"=="末尾用于填充n%
我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i
为什么4.1%2返回0.0999999999999996?但是4.2%2==0.2。 最佳答案 参见此处:WhatEveryProgrammerShouldKnowAboutFloating-PointArithmetic实数是无限的。计算机使用的位数有限(今天是32位、64位)。因此计算机进行的浮点运算不能代表所有的实数。0.1是这些数字之一。请注意,这不是与Ruby相关的问题,而是与所有编程语言相关的问题,因为它来自计算机表示实数的方式。 关于ruby-为什么4.1%2使用Ruby返
鉴于我有以下迁移:Sequel.migrationdoupdoalter_table:usersdoadd_column:is_admin,:default=>falseend#SequelrunsaDESCRIBEtablestatement,whenthemodelisloaded.#Atthispoint,itdoesnotknowthatusershaveais_adminflag.#Soitfails.@user=User.find(:email=>"admin@fancy-startup.example")@user.is_admin=true@user.save!ende
我正在使用active_admin,我在Rails3应用程序的应用程序中有一个目录管理,其中包含模型和页面的声明。时不时地我也有一个类,当那个类有一个常量时,就像这样:classFooBAR="bar"end然后,我在每个必须在我的Rails应用程序中重新加载一些代码的请求中收到此警告:/Users/pupeno/helloworld/app/admin/billing.rb:12:warning:alreadyinitializedconstantBAR知道发生了什么以及如何避免这些警告吗? 最佳答案 在纯Ruby中:classA
它不等于主线程的binding,这个toplevel作用域是什么?此作用域与主线程中的binding有何不同?>ruby-e'putsTOPLEVEL_BINDING===binding'false 最佳答案 事实是,TOPLEVEL_BINDING始终引用Binding的预定义全局实例,而Kernel#binding创建的新实例>Binding每次封装当前执行上下文。在顶层,它们都包含相同的绑定(bind),但它们不是同一个对象,您无法使用==或===测试它们的绑定(bind)相等性。putsTOPLEVEL_BINDINGput
我可以得到Infinity和NaNn=9.0/0#=>Infinityn.class#=>Floatm=0/0.0#=>NaNm.class#=>Float但是当我想直接访问Infinity或NaN时:Infinity#=>uninitializedconstantInfinity(NameError)NaN#=>uninitializedconstantNaN(NameError)什么是Infinity和NaN?它们是对象、关键字还是其他东西? 最佳答案 您看到打印为Infinity和NaN的只是Float类的两个特殊实例的字符串
如果您尝试在Ruby中的nil对象上调用方法,则会出现NoMethodError异常并显示消息:"undefinedmethod‘...’fornil:NilClass"然而,有一个tryRails中的方法,如果它被发送到一个nil对象,它只返回nil:require'rubygems'require'active_support/all'nil.try(:nonexisting_method)#noNoMethodErrorexceptionanymore那么try如何在内部工作以防止该异常? 最佳答案 像Ruby中的所有其他对象