【发布时间】:2018-02-24 10:27:24
【问题描述】:
我正在努力让我的 Android 应用成为后 Android M 世界的好公民,这对应用在设备打瞌睡时可以/不能做什么施加了严格的限制。我对所涉及的问题的理解还比较零散,所以我希望这里有人可以填补空白。
打瞌睡的持续时间
我自己的经验发现
- 在静止、屏幕关闭、不活动大约半小时内开始打瞌睡
- 第一个维护窗口发生在 30 分钟内
- 下一个发生在大约一个小时后
- 在 ca 2、4 和 6 小时之后的那些。除此之外,我还没有测试过
这些是官方的 Android 打瞌睡期还是只是一种经验观察。
以上所有内容均在 Android N 设备上。
在打盹模式下测试应用
- 使用 ADB 将设备连接到计算机
- 将应用程序置于前台
- 关闭设备屏幕
- 来自命令行问题
adb shell dumpsys battery unplug - 现在循环执行命令 `adb shell dumpsys deviceidle step light OR deep
- 终于发出
adb shell dumpsys battery reset
进入/退出打瞌睡
在屏幕关闭且设备未受到移动时发生
大概这使用了手机中的运动传感器,所以安静地坐在非常平稳移动的火车上的手机仍然会打瞌睡?
如果我拿起一部打瞌睡的手机并开始带着它四处走动而没有与之交互,它会自动退出打盹吗?
假设我的应用程序在其主机设备进入休眠状态时不在前台。然后我再次开始使用该设备,但没有访问该应用程序。它会自动重新开始“工作”吗,即
它的广播接收器会起作用吗?
它的处理程序将开始工作?
setRequiresDeviceIdle(true)的计划作业将停止被调用吗?
打盹和作业调度的各种模式
据我了解,有两种打瞌睡模式 LIGHT 和 DEEP。它们都有子模式
LIGHT:活动、空闲、空闲_维护、覆盖。我不明白各种模式的作用。我从 ADB 发出了
step light,屏幕打开并看到了返回值ACTIVE。关闭屏幕step light返回IDLE。DEEP:Active,IDLE_PENDING,SENSING,LOCATING,IDLE,IDLE_MAINTENANCE 屏幕打开也返回
ACTIVE,但屏幕关闭时返回IDLE_PENDING。那么其他子模式,IDLE,SENSING...什么时候发生呢?
我假设IDLE_MAINTENANCE 发生在设备从 DOZE 进入维护窗口并尝试运行来自各种应用的待处理作业请求时。
但如果是这种情况,为什么当我在应用程序中的计划作业运行时检查PowerManager.isDeviceIdleMode() 和PowerManger.isPowerSaveMode()总是返回false?
JobInfo.Builder 非常友好地允许您设置诸如setMinimumLatency 和setOverrideDeadline 之类的标准,但据我所知,OS hen 去并愉快地忽略它们 - 有时我的工作在几秒钟内运行其他时间相隔两个小时。
为什么没有 API 函数来测试 Doze 及其子模式?我希望在PowerManager 中找到它,但我发现只有isDeviceIdleMode 和isPowerSaveMode 在测试时始终返回false
打盹模式下的应用
会所有其后台服务被破坏吗?
不会得到正常的优先级推送消息?
不会响应警报 - 但除了
setAndAllowWhenIdle之外是吗?不会从它的任何广播接收器中获得任何通信?
将无法通过套接字连接到外部世界 - 所以推送消息、发布/订阅等将不起作用?
将立即销毁 Android 清单中声明的所有广播接收器。这是我自己的发现 - 我从 Java 代码创建的接收器保持不变,尽管它们在打瞌睡时不起作用。
我自己的应用通过设置广播接收器并调用.FusedLocationApi.requestLocationUpdates 来监视地理位置变化。此接收器在打盹/唤醒周期中存活。但是,是否可以保证我的LocationUpdates 请求在醒来后仍然会得到兑现?
我遇到了一个相当奇怪的错误。我发现我在打瞌睡中安排的工作在某些情况下运行得太近了,即使我给它们提供了 900,000 毫秒(15 分钟)的延迟和 1,000,000 毫秒的截止日期。我想我可以通过跟踪我这样做的最后一次运行时间来测试最后一次运行作业的时间来解决这个问题
private static Boolean shortInstantGap()
{
Long instantNow = Instant.now().getEpochSecond();
if (300 > (instantNow - this.lastInstant)) return true;
//ignore the job opportunity if the last one was
//less than 300s (5 minutes) ago
this.lastInstant = instantNow;
return false;
}
然后中止作业槽
private static Runnable timeRunner = new Runnable()
{
@Override
public void run()
{
if (shortInstantGap()) return;
callMyHandlerCode();
}
};
但是,我发现当我通过屏幕关闭屏幕打开周期时,如果它在屏幕上,此代码会导致操作系统突然终止我的应用程序。为什么会这样?
最后,是不是没有一个 API 调用我可以用来测试设备刚刚从打瞌睡状态恢复,以便我有机会做一些打瞌睡后的内务处理?
【问题讨论】:
-
你在这里问了很多问题。我会修剪它。您可以轻松地将其分成两个独立但相互关联的问题。我想回答,但要解决的问题太多了。
-
很多重要的问题,太糟糕了,所以像往常一样不屑一顾:) 你找到答案了吗?我真的可以利用这些知识。
-
很遗憾,不是。我已经为自己找到了一些答案,但绝不是全部。我可能会在某个时候用我自己的答案更新这个帖子。
-
请问有人找到解决方案了吗?
标签: android-6.0-marshmallow android-doze