在 BroadcastReceiver 中获取 WakeLock 并在 Service 中释放它的正确模式
即使经过大量研究,我仍然不能完全确定为 BroadcastReceiver
启动的 Service
实现 WakeLock
的方式是否正确- 尽管它看起来工作正常。广播接收器获取从警报发送给它的意图,因此首先从 AlarmManager
的 API 文档开始:
如果您的警报接收器调用了 Context.startService(),则有可能 在启动请求的服务之前手机将进入睡眠状态。到 防止这种情况发生,您的广播接收器和服务将需要 实施单独的唤醒锁定策略以确保手机 继续运行,直到服务可用。
因此,在 onReceive() 中我这样做:
Intent serviceIntent = new Intent(context, SomeService.class);
context.startService(serviceIntent);
if(SomeService.wakeLock == null) {
PowerManager powerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
SomeService.wakeLock = powerManager.newWakeLock(
PowerManager.PARTIAL_WAKE_LOCK,
SomeService.WAKE_LOCK_TAG);
}
if(! SomeService.wakeLock.isHeld()) {
SomeService.wakeLock.acquire();
}
在服务中我这样做:
try {
// Do some work
} finally {
if(wakeLock != null) {
if(wakeLock.isHeld()) {
wakeLock.release();
}
wakeLock = null;
}
}
SomeService.wakeLock 字段是包私有的、静态的和易失性的。
我不确定的是使用 isHeld()
进行的检查 - 它是否真的告诉我是否获取了 WakeLock
,以及我是否需要进行此检查?
Even after a lot of research I am still not completely sure if the way how I implement a WakeLock
for a Service
started by a BroadcastReceiver
is correct - even though it seems to work fine. The broadcast receiver gets intents sent to it from an alarm, so to start with, from the API docs of AlarmManager
:
If your alarm receiver called Context.startService(), it is possible
that the phone will sleep before the requested service is launched. To
prevent this, your BroadcastReceiver and Service will need to
implement a separate wake lock policy to ensure that the phone
continues running until the service becomes available.
So, in onReceive()
I do:
Intent serviceIntent = new Intent(context, SomeService.class);
context.startService(serviceIntent);
if(SomeService.wakeLock == null) {
PowerManager powerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
SomeService.wakeLock = powerManager.newWakeLock(
PowerManager.PARTIAL_WAKE_LOCK,
SomeService.WAKE_LOCK_TAG);
}
if(! SomeService.wakeLock.isHeld()) {
SomeService.wakeLock.acquire();
}
and in the service I do:
try {
// Do some work
} finally {
if(wakeLock != null) {
if(wakeLock.isHeld()) {
wakeLock.release();
}
wakeLock = null;
}
}
The SomeService.wakeLock
field is package private, static and volatile.
What I am unsure about is the check using isHeld()
- does it really tell me if a WakeLock
is acquired or not, and do I need to do this check at all?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
其实回答起来有点棘手。查看
PowerManager
和PowerManager.WakeLock
的源代码 此处WakeLock.acquire()
和WakeLock.acquireLocked()方法如下...
...
mService
是一个IPowerManager
接口,并且它的源代码不可用,因此很难判断什么时候可能会出现问题,也可能不会出现问题尝试调用acquireWakeLock(...)
。无论如何,唯一可以捕获的异常是
RemoteException
并且catch
块不执行任何操作。在 try/catch 之后,mHeld
立即被设置为true
。简而言之,如果您在
acquire()
之后立即调用isHeld()
,结果将始终为true
。进一步查看 PowerManager.WakeLock 的源代码,可以看到
release()
的类似行为,它调用release(int flags)
,其中mHeld无论发生什么情况,
成员始终设置为false
。总之,我建议检查
isHeld()
始终是一个好主意,作为最佳实践,以防更高版本的 Android 更改WakeLock
方法的这种行为。Actually slightly tricky to answer. Looking at the source for
PowerManager
andPowerManager.WakeLock
here theWakeLock.acquire()
andWakeLock.acquireLocked()
methods are as follows......
mService
is anIPowerManager
interface and the source for it isn't available so it's hard to tell what may or may not go wrong when attempting to callacquireWakeLock(...)
.In any case, the only exception that can be caught is
RemoteException
and thecatch
block does nothing. Immediately after the try/catch,mHeld
is settrue
regardless.In short, if you call
isHeld()
immediately afteracquire()
the result will always betrue
.Looking further into the source for
PowerManager.WakeLock
shows similar behaviour forrelease()
which callsrelease(int flags)
where themHeld
member is always set tofalse
regardless of what happens.In conclusion I'd suggest it is always a good idea to check
isHeld()
just as a best practice in case later versions of Android change this behaviour of theWakeLock
methods.在单例中管理您的wakeLock(通过所有上下文和对象访问的唯一实例)
使用自定义类的单例实例,然后您可以从调用到调用中获取唤醒锁对象引用,
这里有一个单例示例
在您的应用程序中处理“唤醒锁”对象,您可以像这样访问它
Manage you wakeLock inside a singleton (unique instance accessible through all your context and object)
Use a singleton instance of a custom class, then you may get wakelock object reference from call to call ,
here an singleton example
in your application to handle your "wakelock" object your may access it like
所有这些工作都可以通过名为 WakefulBroadcastReceiver
All this job can be done by a helper and native class called WakefulBroadcastReceiver
可能是更好的方法
我认为 android.os.Messenger对于接收者来说
:对于服务:
即使 service & ,此方法也可以正常工作。接收器在不同的进程中运行。
I think android.os.Messenger may be a better way
for the receiver:
for the service:
This method work properly even if service & receiver run in different process.