tag studio power manager invalid developer android service broadcastreceiver wakelock

invalid - power manager android studio



PatrĂ³n correcto para adquirir un WakeLock en un BroadcastReceiver y lanzarlo en un Servicio (4)

Incluso después de mucha investigación, todavía no estoy completamente seguro de si la forma en que implemento un WakeLock para un Service iniciado por un BroadcastReceiver es correcta, aunque parece que funciona bien. El receptor de difusión recibe intenciones desde una alarma, así que para empezar, desde los documentos API del AlarmManager :

Si su receptor de alarma llamado Context.startService (), es posible que el teléfono se ponga en reposo antes de que se inicie el servicio solicitado. Para evitar esto, su BroadcastReceiver y su Servicio deberán implementar una política de bloqueo de activación separada para garantizar que el teléfono continúe funcionando hasta que el servicio esté disponible.

Entonces, en onReceive() hago:

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

y en el servicio que hago:

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

El campo SomeService.wakeLock es un paquete privado, estático y volátil.

Lo que no estoy seguro es sobre el cheque que utiliza isHeld() . ¿Realmente me dice si se adquirió un WakeLock o no, y tengo que hacer este chequeo?


Lo que no estoy seguro es sobre el cheque que utiliza isHeld() . ¿Realmente me dice si se adquirió un WakeLock o no, y tengo que hacer este chequeo?

En realidad un poco difícil de responder. En cuanto a la fuente de PowerManager y PowerManager.WakeLock here los WakeLock.acquire() y WakeLock.acquireLocked() son los siguientes ...

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 es una interfaz de IPowerManager y la fuente no está disponible, por lo que es difícil decir qué puede fallar o no al intentar llamar acquireWakeLock(...) .

En cualquier caso, la única excepción que se puede capturar es RemoteException y el bloque catch no hace nada. Inmediatamente después de la prueba / captura, mHeld se establece como true .

En resumen, si llama a isHeld() inmediatamente después de acquire() el resultado siempre será true .

Buscando más en la fuente de PowerManager.WakeLock muestra un comportamiento similar para release() que llama a release(int flags) donde el miembro mHeld siempre se establece en false independientemente de lo que suceda.

En conclusión, sugiero que siempre es una buena idea comprobar isHeld() como una mejor práctica en caso de que versiones posteriores de Android cambien este comportamiento de los métodos de WakeLock .


Administre su wakeLock dentro de un singleton (instancia única accesible a través de todo su contexto y objeto)

Use una instancia de singleton de una clase personalizada, luego puede obtener una referencia de objeto wakelock de llamada a llamada,



aquí un ejemplo singleton

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


en su aplicación para manejar su objeto "wakelock" al que puede acceder como

// set a created wakelock MyData.getInstance().setMyWakeLock(wl); // get the saved wakelock object PowerManager.WakeLock obj = MyData.getInstance().getMyWakeLock();


Creo que android.os.Messenger puede ser una mejor manera

para el receptor:

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

para el servicio:

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

Este método funciona correctamente incluso si el servicio y el receptor se ejecutan en un proceso diferente.