正确的模式来获取BroadcastReceiver中的WakeLock并将其释放到服务中

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

如果您的警报接收器调用了Context.startService(),则在请求的服务启动之前,手机可能会睡眠。 为了防止这种情况发生,您的BroadcastReceiver和Service将需要实施一个单独的唤醒locking策略,以确保电话继续运行,直到服务可用。

所以,在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

总之,如果在acquire()之后立即调用isHeld() acquire() ,结果将始终为true

进一步查看PowerManager.WakeLock的源代码,显示类似于release()行为,它调用release(int flags) ,无论发生什么, mHeld成员总是被设置为false

总之,我build议检查isHeld()是一个好主意,这是最好的做法,以防Android的更新版本改变WakeLock方法的这种行为。

在单身人士内部pipe理你的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; } } 

在你的应用程序中处理你的“唤醒”对象,你可以像访问它

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

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