在 BroadcastReceiver 中获取 WakeLock 并在 Service 中释放它的正确模式 [英] Correct pattern to acquire a WakeLock in a BroadcastReceiver and release it in a Service

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

问题描述

即使经过大量研究,我仍然不完全确定我如何为 BroadcastReceiver 启动的 Service 实现 WakeLock> 是正确的 - 即使它似乎工作正常.广播接收器从警报中获取发送给它的意图,因此从 AlarmManager 的 API 文档开始:

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:

如果你的报警接收器调用了Context.startService(),有可能手机将在请求的服务启动之前休眠.到防止这种情况,您的 BroadcastReceiver 和 Service 将需要实施单独的唤醒锁定策略,以确保手机继续运行,直到服务可用.

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.

所以,在 onReceive() 中,我这样做:

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();
    }

在我所做的服务中:

    try {
        // Do some work
    } finally {
        if(wakeLock != null) {
            if(wakeLock.isHeld()) {
                wakeLock.release();
            }
            wakeLock = null;
        }
    }

SomeService.wakeLock 字段是包私有的、静态的和易变的.

The SomeService.wakeLockfield is package private, static and volatile.

我不确定的是使用 isHeld() 的检查 - 它是否真的告诉我是否获取了 WakeLock,我是否需要这样做检查一下?

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?

推荐答案

我不确定的是使用 isHeld() 的检查 - 它是否真的告诉我是否获取了 WakeLock,我是否需要这样做检查一下?

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?

实际上回答起来有点棘手.查看 PowerManagerPowerManager.WakeLock 的源代码 这里 WakeLock.acquire()WakeLock.acquireLocked()方法如下...

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 是一个 IPowerManager 接口,它的来源不可用,因此很难判断在尝试调用时可能出错或不出错acquireWakeLock(...).

...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(...).

无论如何,唯一可以捕获的异常是 RemoteExceptioncatch 块什么也不做.在 try/catch 之后,mHeld 立即被设置为 true.

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.

简而言之,如果您在 acquire() 之后立即调用 isHeld(),结果将始终为 true.

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

进一步查看 PowerManager.WakeLock 的源代码显示了 release() 的类似行为,它调用 release(int flags),其中 release()无论发生什么,code>mHeld 成员始终设置为 false.

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.

总而言之,我建议检查 isHeld() 总是一个好主意,作为最佳实践,以防以后的 Android 版本更改 WakeLock 方法.

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.

这篇关于在 BroadcastReceiver 中获取 WakeLock 并在 Service 中释放它的正确模式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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