use*_*032 26 android android-service android-location android-lifecycle android-doze
我正在尝试创建一个允许用户记录路线(位置/ GPS)的应用程序.为了确保即使屏幕关闭也会记录位置,我已经foreground service为位置记录创建了一个.我将位置存储在一个Room Database注入我的服务中的位置Dagger2.
但是,这项服务被Android杀死,当然这并不好.我可以订阅低内存警告,但这并没有解决我的服务在运行Android 8.0的现代高端手机上大约30分钟后被杀的根本问题
我创建了一个只有"Hello world"活动和服务的最小项目:https://github.com/RandomStuffAndCode/AndroidForegroundService
该服务在我的Application课程中启动,路由记录通过以下方式启动Binder:
// Application
@Override
public void onCreate() {
super.onCreate();
mComponent = DaggerAppComponent.builder()
.appModule(new AppModule(this))
.build();
Intent startBackgroundIntent = new Intent();
startBackgroundIntent.setClass(this, LocationService.class);
startService(startBackgroundIntent);
}
// Binding activity
bindService(new Intent(this, LocationService.class), mConnection, Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT);
// mConnection starts the route logging through `Binder` once connected. The binder calls startForeground()
Run Code Online (Sandbox Code Playgroud)
我可能不需要BIND_AUTO_CREATE旗帜,我一直在测试不同的旗帜,试图不让我的服务被杀 - 到目前为止没有运气.
使用分析器看起来我没有任何内存泄漏,内存使用率稳定在~35mb:
使用adb shell dumpsys activity processes > tmp.txt我可以确认,foregroundServices=true我的服务列在LRU列表中的第8位:
Proc # 3: prcp F/S/FGS trm: 0 31592:com.example.foregroundserviceexample/u0a93 (fg-service)
似乎无法创建一个您可以信任的前台服务,以免被杀死.所以,我们能做些什么?好...
START_STICKY.这似乎有点浪费,并没有导致非常漂亮的代码,但它可能会工作......有点.根据Android杀死服务后重新创建服务所需的时间,很大一部分地点可能会丢失.这真的是在Android背景下做事情的当前状态吗?有没有更好的方法?
编辑:将应用程序列入白名单以进行电池优化(禁用它)并不会阻止我的服务被杀死
编辑:Context.startForegroundService()用于启动服务并不能改善这种情况
编辑:所以这确实只发生在某些设备上,但它始终存在于它们上面.我想你必须选择不支持大量用户或编写非常难看的代码.真棒.
leo*_*mer 21
由startForegroundbesongs 开始的服务到第二个最重要的组可见过程:
一个可见的过程正在进行用户当前意识到的工作,因此杀死它会对用户体验产生明显的负面影响.在以下条件下,可以看到一个过程:
它正在运行一个活动,该活动在屏幕上对用户可见,但不在前台(已调用其onPause()方法).例如,如果前景活动显示为允许在其后面看到前一个活动的对话框,则可能会发生这种情况.
它有一个作为前台服务运行的服务,通过Service.startForeground()(它要求系统将服务视为用户知道或基本上对他们可见的东西).
- 它正在托管系统用于用户知道的特定功能的服务,例如动态壁纸,输入法服务等.
在系统中运行的这些进程的数量比前台进程更少,但仍然是相对受控的.这些进程被认为是非常重要的,除非需要这样做以保持所有前台进程运行,否则不会被杀死.
话虽这么说,你永远不能确定你的服务在任何时候都不会被杀死.例如记忆压力,电池电量不足等.看看谁死了,谁死了.
对于如何处理它,基本上你自己回答了这个问题.要走的路是START_STICKY:
对于已启动的服务,他们可以决定运行另外两种主要操作模式,具体取决于它们返回的值
onStartCommand():START_STICKY是否用于根据需要显式启动和停止的服务,同时START_NOT_STICKY或START_REDELIVER_INTENT用于仅应保持运行的服务处理发送给他们的任何命令.有关语义的更多详细信息,请参阅链接的文档.
作为一般准则,您应该在后台(矿石前景)服务中尽可能少地执行,即仅进行位置跟踪并将其他所有内容保留在前台活动中.只有跟踪应该需要很少的配置才能快速加载.此外,您的服务越小,被杀的可能性就越小.您的活动将在系统进入后台之前的状态下恢复,只要它没有被杀死.另一方面,前景活动的"冷启动"应该不是问题.
我不认为这很难看,因为这可以保证手机始终为用户提供最佳体验.这是它必须做的最重要的事情.有些设备在30分钟后关闭服务(可能没有用户交互)是不幸的.
所以,正如你所说,你必须这样做
在例如房间数据库中保留服务中的所有内容.每个变量,每个自定义类,每次更改任何变量,然后使用START_STICKY启动服务.
请参阅创建永无止境的服务
隐含的问题:
根据Android杀死服务后重新创建服务所需的时间,很大一部分地点可能会丢失.
这通常只需要很短的时间.特别是因为您可以使用Fused Location Provider Api进行位置更新,这是一个独立的系统服务,不太可能被杀死.所以它主要取决于你需要重新创建服务的时间onStartCommand.
另请注意,从Android 8.0开始,您需要使用a,
forground service因为背景位置限制.
编辑:最近新闻报道:有些制造商可能会给你一个很难保持服务运行的时间.该网站https://dontkillmyapp.com/会跟踪您的设备的制造商和可能的缓解措施.Oneplus目前(29.01.19)是最严重的罪犯之一.
在推出1 + 5和1 + 6手机时,OnePlus推出了迄今为止市场上最严苛的背景限制之一,甚至使小米或华为的手机相形见绌.用户不仅需要启用额外的设置才能使他们的应用程序正常运行,但这些设置甚至会通过固件更新重置,以便应用程序再次中断,并且用户需要定期重新启用这些设置.
用户解决方案
关闭系统设置>应用程序>齿轮图标>特殊访问>电池优化.
遗憾的是有
开发人员端没有已知的解决方案
我知道为时已晚,但这可能对某些人有所帮助。我也面临着同样的问题,即保持前台服务处于活动状态而不会被不同制造商的操作系统杀死。即使将前台服务添加到例外列表(电池、清洁器等)并允许自动启动,大多数中国制造商的操作系统也会终止前台服务。
我找到了这个链接,它解决了我长期以来保持服务活跃的问题。
您所要做的就是在单独的进程中运行您的前台服务。就是这样。
您可以通过android:process在您的 AndroidManifest.xml 中添加到您的服务来做到这一点。
例如:
<service android:name=".YourService"
android:process=":yourProcessName" />
Run Code Online (Sandbox Code Playgroud)
您可以参考文档以了解更多信息android:process
编辑: SharedPreferences 不能跨多个进程工作。在这种情况下,您必须使用 IPC(进程间通信)方法,或者您可以使用它ContentProviders来存储和访问要跨进程使用的数据。来自docs。
| 归档时间: |
|
| 查看次数: |
8112 次 |
| 最近记录: |