正确的模式,以获取BroadcastReceiver中的WakeLock并在服务中释放它

即使经过大量的研究,我仍然不能完全确定我如何实现一个由BroadcastReceiver启动的ServiceWakeLock是正确的 – 即使它似乎工作正常。 广播接收器从警报发送到它的意图,所以从AlarmManager的API文档AlarmManager

如果您的警报接收器调用了Context.startService(),则手机可能会在启动所请求的服务之前hibernate。 为防止这种情况发生,您的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 ,我是否需要进行此检查?

Solutions Collecting From Web of "正确的模式,以获取BroadcastReceiver中的WakeLock并在服务中释放它"

我不确定的是使用isHeld()的检查 – 它是否真的告诉我是否获得了WakeLock ,我是否需要进行此检查?

实际上回答有些棘手。 在这里查看PowerManagerPowerManager.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(...)时很难分辨出可能出错或可能出现的错误。

在任何情况下,唯一可以捕获的exception是RemoteExceptioncatch块什么也不做。 在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); } } 

即使服务和接收器在不同的进程中运行,此方法也能正常工作。