本文介绍了正确的方式来获取WakeLock在一个BroadcastReceiver和服务将其释放的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

即使经过了大量的研究,我还没有完全确定,如果我如何实现方式 WakeLock 服务开始由的BroadcastReceiver 是正确的 - 尽管它似乎很好地工作。广播接收器会从警报发送给它的,所以下手意图,从API文档 AlarmManager

所以,在的onReceive()我做的:

 意图serviceIntent =新的意图(背景下,SomeService.class);
    context.startService(serviceIntent);

    如果(SomeService.wakeLock == NULL){
        电源管理器电源管理器=(电源管理器)context.getSystemService(Context.POWER_SERVICE);
        SomeService.wakeLock = powerManager.newWakeLock(
                PowerManager.PARTIAL_WAKE_LOCK,
                SomeService.WAKE_LOCK_TAG);
    }
    如果(!SomeService.wakeLock.isHeld()){
        SomeService.wakeLock.acquire();
    }
 

在我做的服务:

 尝试{
        //做一些工作
    } 最后 {
        如果(wakeLock!= NULL){
            如果(wakeLock.isHeld()){
                wakeLock.release();
            }
            wakeLock = NULL;
        }
    }
 

SomeService.wakeLock 字段是包私有,静态震荡。

我不能确定的是使用支票 isHeld() - 它真的告诉我,如果一个 WakeLock 被收购与否,做我需要做这个检查呢?

解决方案

其实有点难回答。纵观源电源管理器 PowerManager.WakeLock 这里的 WakeLock.acquire() WakeLock.acquireLocked()方法如下所示...

 公共无效的获取(长期超时){
    同步(mToken){
        acquireLocked();
        mHandler.postDelayed(mReleaser,超时);
    }
}

私人无效acquireLocked(){
    如果(!mRefCounted || mCount ++ == 0){
        //做到这一点,即使唤醒锁已被认为是举行(mHeld ==真)
        //因为非引用计数的唤醒锁并不总是正确释放。
        //例如,键盘锁的苏醒锁定可能被强制地由释放
        //不知道键盘保护电源管理器。随后调用收购
        //应立即尽管永远不必再次购买之后锁
        //被明确​​释放了键盘锁。
        mHandler.removeCallbacks(mReleaser);
        尝试 {
            mService.acquireWakeLock(mToken,mFlags,MTAG,mWorkSource);
        }赶上(RemoteException的E){
        }
        mHeld = TRUE;
    }
}
 

... MSERVICE IPowerManager 接口和源,因为这是不可用,所以很难告诉什么可以或试图打电话的时候,可能不会出错 acquireWakeLock(...)

在任何情况下,可以被捕获的唯一的例外是的RemoteException 块什么都不做。紧随try / catch语句之后, mHeld 设置不管。

总之,如果你调用 isHeld()后立即获取()的结果总是

展望更远的进入源 PowerManager.WakeLock 显示了类似的行为发布()这就要求发布(I​​NT标志)其中 mHeld 成员始终设置为不管发生什么事。

在最后,我会建议它始终是一个好主意,检查 isHeld()一样的情况下后面的变化的Andr​​oid版本的这种行为,最好的做法 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:

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.wakeLockfield 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?

解决方案

Actually slightly tricky to answer. Looking at the source for PowerManager and PowerManager.WakeLock here the WakeLock.acquire() and WakeLock.acquireLocked() methods are as follows...

public void acquire(long timeout) {
    synchronized (mToken) {
        acquireLocked();
        mHandler.postDelayed(mReleaser, timeout);
    }
}

private void acquireLocked() {
    if (!mRefCounted || mCount++ == 0) {
        // Do this even if the wake lock is already thought to be held (mHeld == true)
        // because non-reference counted wake locks are not always properly released.
        // For example, the keyguard's wake lock might be forcibly released by the
        // power manager without the keyguard knowing.  A subsequent call to acquire
        // should immediately acquire the wake lock once again despite never having
        // been explicitly released by the keyguard.
        mHandler.removeCallbacks(mReleaser);
        try {
            mService.acquireWakeLock(mToken, mFlags, mTag, mWorkSource);
        } catch (RemoteException e) {
        }
        mHeld = true;
    }
}

...mService is an IPowerManager 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 call acquireWakeLock(...).

In any case, the only exception that can be caught is RemoteException and the catch block does nothing. Immediately after the try/catch, mHeld is set true regardless.

In short, if you call isHeld() immediately after acquire() the result will always be true.

Looking further into the source for PowerManager.WakeLock shows similar behaviour for release() which calls release(int flags) where the mHeld member is always set to false 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 the WakeLock methods.

这篇关于正确的方式来获取WakeLock在一个BroadcastReceiver和服务将其释放的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-26 14:46