Commonsware的 WakefulIntentService 精美的作品,但也有一些事情,我不完全得到。下面是服务的核心 - 的来源:
类WIS扩展IntentService {
私有静态最后字符串名称= WIS.class.getName()+.Lock;
私有静态挥发WakeLock lockStatic = NULL;
同步私有静态PowerManager.WakeLock GETLOCK(上下文的背景下){
如果(lockStatic == NULL){
PowerManager的经理=(电源管理器)上下文
.getSystemService(Context.POWER_SERVICE);
lockStatic = mgr.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,名);
lockStatic.setReferenceCounted(真正的);
}
返回(lockStatic);
}
公共静态无效startWIS(上下文ctxt,意图我){
GETLOCK(ctxt.getApplicationContext())获得()。
ctxt.startService(ⅰ);
}
公共WIS(字符串名称){
超(名称);
setIntentRedelivery(真正的);
}
@覆盖
公众诠释onStartCommand(意向意图,诠释标志,诠释startId){
PowerManager.WakeLock锁= GETLOCK(this.getApplicationContext());
如果(lock.isHeld()||(标志&安培;!START_FLAG_REDELIVERY)= 0){//?
lock.acquire();
}
super.onStartCommand(意向,标志,startId);
返程(START_REDELIVER_INTENT);
}
@覆盖
保护无效onHandleIntent(意向意图){
尝试 {
//做你的事
} 最后 {
PowerManager.WakeLock锁= GETLOCK(this.getApplicationContext());
如果(lock.isHeld())lock.release();
}
}
}
问题
如果进程被杀死刚发生后的的onReceive()
我们的报警接收机的回报?也就是说,如果服务的onCreate()
(如果该服务尚未实例化)或者 onStartCommand()
永远不会运行。 AFAIK杀死一个过程需要它的锁吧。或者,这是一个不可能的情况?
在考虑到previous应(标志和安培; START_FLAG_RETRY)?
添加
为什么如果(!lock.isHeld())
检查?
为什么 this.getApplicationContext()
需要的?是不是这
就够了吗?
解决方案
AFAIK杀死一个过程需要它的锁吧。
正确的。
或者,这是一个不可能的情况?
这是相当不可能的,但绝对不是不可能的。
在考虑到previous应(标志和安培; START_FLAG_RETRY)?加入
这应该由 START_FLAG_REDELIVERY
被覆盖。 AFAIK,与 START_REDELIVER_INTENT
,没有重试
没有开航
。如果你有证据,相反,我很乐意看到它。
为什么,如果(!lock.isHeld())检查?
调用发布()
在 WakeLock
未举行将导致异常。这仅仅是一个安全毯,以确保我们不拉闸引发不必要的异常。从理论上讲,它不应该被需要;从理论上讲,我应该有头发。
为什么this.getApplicationContext()需要的?是不是这样就够了吗?
我们创建一个 WakeLock
,这是我们在一个静态数据成员持有。的也许的的 getSystemService()
调用不拉闸把上下文
里面把它称为在电源管理器
。而且,即使它,的也许的的上下文
将不会被传递到生成的 WakeLock
实例。不过,为了安全起见,使用 getApplicationContext()
,我们得到了 WakeLock
的方式,确保只有上下文
那么我们就可能泄漏是单应用程序上下文,它作为一个单身,实际上是pre-泄露。 : - )
Commonsware's WakefulIntentService works beautifully but there are some things I do not quite get. Below is the core of the service - a stripped down version of the source :
class WIS extends IntentService {
private static final String NAME = WIS.class.getName() + ".Lock";
private static volatile WakeLock lockStatic = null;
synchronized private static PowerManager.WakeLock getLock(Context context) {
if (lockStatic == null) {
PowerManager mgr = (PowerManager) context
.getSystemService(Context.POWER_SERVICE);
lockStatic = mgr.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, NAME);
lockStatic.setReferenceCounted(true);
}
return (lockStatic);
}
public static void startWIS(Context ctxt, Intent i) {
getLock(ctxt.getApplicationContext()).acquire();
ctxt.startService(i);
}
public WIS(String name) {
super(name);
setIntentRedelivery(true);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
PowerManager.WakeLock lock = getLock(this.getApplicationContext());
if (!lock.isHeld() || (flags & START_FLAG_REDELIVERY) != 0) { // ?
lock.acquire();
}
super.onStartCommand(intent, flags, startId);
return (START_REDELIVER_INTENT);
}
@Override
protected void onHandleIntent(Intent intent) {
try {
// do your thing
} finally {
PowerManager.WakeLock lock = getLock(this.getApplicationContext());
if (lock.isHeld()) lock.release();
}
}
}
Questions
What happens if the process is killed just after theonReceive()
of our alarm receiver returns ? That is if service onCreate()
(if the service is not already instantiated) or onStartCommand()
never run. AFAIK a process killed takes its locks with it. Or is this an impossible scenario ?
In view of the previous should (flags & START_FLAG_RETRY)
be added ?
Why the if (!lock.isHeld())
check ?
Why is this.getApplicationContext()
needed ? is not this
enough ?
解决方案
AFAIK a process killed takes its locks with it.
Correct.
Or is this an impossible scenario ?
It's fairly unlikely, but certainly not impossible.
In view of the previous should (flags & START_FLAG_RETRY) be added ?
That should be covered by START_FLAG_REDELIVERY
. AFAIK, with START_REDELIVER_INTENT
, there is no RETRY
without REDELIVERY
. If you have evidence to the contrary, I'd love to see it.
Why the if (!lock.isHeld()) check ?
Calling release()
on a WakeLock
that is not held results in an exception. This is just a safety blanket to ensure we don't wind up throwing an unnecessary exception. In theory, it should never be needed; in theory, I should have hair.
Why is this.getApplicationContext() needed ? is not this enough ?
We create a WakeLock
, which we hold in a static data member. Probably the getSystemService()
call does not wind up putting the Context
that called it inside the PowerManager
. And, even if it did, probably the Context
would not be passed to the resulting WakeLock
instance. However, to be safe, by using getApplicationContext()
, we obtain the WakeLock
in a fashion that ensures that the only Context
we could possibly "leak" is the singleton application context, which, as a singleton, is effectively pre-leaked. :-)