22

多くの調査を行った後でも、aで開始するWakeLockためのaの実装方法が正しいかどうかはまだ完全にはわかりませんが、正常に機能しているように見えます。ブロードキャストレシーバーは、アラームからインテントを送信します。まず、次のAPIドキュメントからインテントを送信します。ServiceBroadcastReceiverAlarmManager

アラームレシーバーがContext.startService()を呼び出した場合、要求されたサービスが起動される前に電話がスリープする可能性があります。これを防ぐために、BroadcastReceiverとServiceは、サービスが利用可能になるまで電話が実行され続けることを保証するために、個別のウェイクロックポリシーを実装する必要があります。

だから、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()-それは本当にaWakeLockが取得されたかどうかを教えてくれますか、そして私はこのチェックを行う必要がありますか?

4

4 に答える 4

4

私が確信していないのは、を使用したチェックですisHeld()-それは本当にaWakeLockが取得されたかどうかを教えてくれますか、そして私はこのチェックを行う必要がありますか?

実際、答えるのは少し難しいです。ソース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;
    }
}

...mServiceIPowerManagerインターフェースであり、そのソースは利用できないため、を呼び出そうとしたときに何がうまくいかないかを判断するのは困難acquireWakeLock(...)です。

いずれにせよ、キャッチできる唯一の例外はRemoteExceptioncatchブロックが何もしないことです。try / catchの直後は、関係なくmHeld設定されtrueます。

つまり、isHeld()直後に呼び出すとacquire()、結果は常にになりますtrue

ソースをさらに調べると、何が起こってもメンバーが常に設定されている呼び出しのPowerManager.WakeLock同様の動作が示されます。release()release(int flags)mHeldfalse

isHeld()結論として、Androidの新しいバージョンでメソッドのこの動作が変更された場合に備えて、ベストプラクティスと同じように常に確認することをお勧めしWakeLockます。

于 2011-08-24T21:42:11.153 に答える
4

シングルトン内で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();
于 2011-08-24T23:49:32.637 に答える
3

このすべての仕事は、 WakefulBroadcastReceiverと呼ばれるヘルパーとネイティブクラスによって行うことができます

于 2016-01-21T09:45:12.427 に答える
0

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

この方法は、サービスとレシーバーが異なるプロセスで実行されている場合でも正しく機能します。

于 2016-08-07T16:15:46.633 に答える