[英]Correct pattern for BroadcastReceiver getting wakelock to start an Activity?
[英]Correct pattern to acquire a WakeLock in a BroadcastReceiver and release it in a Service
即使经过大量研究,我仍然不能完全确定如何实现一个由BroadcastReceiver
启动的Service
WakeLock
的方式是正确的 - 即使它似乎工作正常。 广播接收器从警报发送到它的意图,所以从AlarmManager
的API文档AlarmManager
:
如果您的警报接收器调用了Context.startService(),则手机可能会在启动所请求的服务之前休眠。 为了防止这种情况,您的BroadcastReceiver和服务需要实施单独的唤醒锁定策略,以确保电话继续运行,直到服务可用。
所以,在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
,我是否需要进行此检查?
我不确定的是使用
isHeld()
的检查 - 它是否真的告诉我是否获得了WakeLock
,我是否需要进行此检查?
实际上回答有些棘手。 在这里查看PowerManager
和PowerManager.WakeLock
的源代码, WakeLock.acquire()
和WakeLock.acquireLocked()
方法如下......
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(...)
时很难分辨出可能出错或可能出现的错误。
在任何情况下,唯一可以捕获的异常是RemoteException
, catch
块什么也不做。 在try / catch之后, mHeld
都设置为true
。
简而言之,如果在acquire()
之后立即调用isHeld()
acquire()
,结果将始终为true
。
进一步查看PowerManager.WakeLock
的源代码显示了release()
类似行为,它调用release(int flags)
,无论发生什么, mHeld
成员总是设置为false
。
总之,我建议检查isHeld()
总是一个好主意,以便在以后版本的Android更改WakeLock
方法的这种行为时作为最佳实践。
在单例内管理wakeLock(可通过所有上下文和对象访问的唯一实例)
使用自定义类的单例实例,然后您可以从调用到调用获取唤醒锁对象引用,
这里是一个单例的例子
class MyData {
private static MyData mMydata= null; // unique reference ( singleton objet container)
private PowerManager.Wakelock myobject = null; // inside the unique object container we have the unique working object to be use by the application
// can't make instance from outside... we want to have single instance
// we want that outside use method "getInstance" to be able to use the object
private MyData() {
}
// retrieve and/or create new unique instance
public static MyData getInstance() {
if (mMydata == null) mMyData = new MyData();
return mMyData;
}
// Works with your memory stored object
// get...
public PowerManager.WakeLock getMyWakelock() {
return myobject;
}
// set ...
public void setMyWakeLock(PowerManager.WakeLock obj) {
myobject = obj;
}
}
在您的应用程序中处理您的“wakelock”对象,您可以访问它
// set a created wakelock
MyData.getInstance().setMyWakeLock(wl);
// get the saved wakelock object
PowerManager.WakeLock obj = MyData.getInstance().getMyWakeLock();
所有这些工作都可以通过一个名为WakefulBroadcastReceiver的帮助程序和本机类来完成
我认为android.os.Messenger可能是更好的方式
对于接收者:
public class MessengerReceiver extends BroadcastReceiver {
private static final String TAG = "MessengerReceiver";
private final MessengerHandler mHandler = new MessengerHandler();
@Override
public void onReceive(Context context, Intent intent) {
// TODO: This method is called when the BroadcastReceiver is receiving
// an Intent broadcast.
mHandler.mWakeLock = ((PowerManager)context.getSystemService(Service.POWER_SERVICE)).newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "myreceiver");
mHandler.mWakeLock.acquire();
Log.e(TAG, "onReceive:: mHandler.mWakeLock=" + mHandler.mWakeLock + ", intent=" + intent + ", this=" + this);
context.startService(new Intent(context, MessengerService.class).putExtra("messenger", new Messenger(mHandler)));
}
static class MessengerHandler extends Handler {
WakeLock mWakeLock;
@Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
if(mWakeLock != null){
mWakeLock.release();
Log.e(TAG, "handleMessage:mWakeLock=" + mWakeLock);
}
super.handleMessage(msg);
}
}
}
为服务:
public class MessengerService extends Service {
private static final String TAG = "MessengerService";
public MessengerService() {
}
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// TODO Auto-generated method stub
Log.e(TAG, "onStartCommand:: intent=" + intent);
final Messenger messenger = intent.getParcelableExtra("messenger");
try {
messenger.send(Message.obtain());
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return super.onStartCommand(intent, flags, startId);
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.