正确的方式来获取WakeLock在一个BroadcastReceiver和服务将其释放 [英] Correct pattern to acquire a WakeLock in a BroadcastReceiver and release it in a Service

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

问题描述

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

  

如果您的报警接收器称为Context.startService(),有可能   该手机将睡眠所请求的服务启动之前。至   prevent这一点,你的BroadcastReceiver和服务需要   实现单独的唤醒锁定策略,以确保手机   继续运行,直到服务变得可用。

所以,在的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 被收购与否,做我需要做这个检查呢?

解决方案
  

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

其实有点难回答。纵观源电源管理器 PowerManager.WakeLock <一个href="https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/core/java/android/os/PowerManager.java"相对=nofollow>这里的 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:

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

解决方案

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和服务将其释放的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆