Android 保持設(shè)備喚醒

2018-08-02 18:24 更新

編寫:jdneo - 原文:http://developer.android.com/training/scheduling/wakelock.html

為了避免電量過度消耗,Android設(shè)備會在被閑置之后迅速進入睡眠狀態(tài)。然而有時候應(yīng)用會需要喚醒屏幕或者是喚醒CPU并且保持它們的喚醒狀態(tài),直至一些任務(wù)被完成。

想要做到這一點,所采取的方法依賴于應(yīng)用的具體需求。但是通常來說,我們應(yīng)該使用最輕量級的方法,減小其對系統(tǒng)資源的影響。在接下來的部分中,我們將會描述在設(shè)備默認(rèn)的睡眠行為與應(yīng)用的需求不相符合的情況下,我們應(yīng)該如何進行對應(yīng)的處理。

保持屏幕常亮

某些應(yīng)用需要保持屏幕常亮,比如游戲與視頻應(yīng)用。最好的方式是在你的Activity中(且僅在Activity中,而不是在Service或其他應(yīng)用組件里)使用FLAG_KEEP_SCREEN_ON屬性,例如:

public class MainActivity extends Activity {
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
  }

該方法的優(yōu)點與喚醒鎖(Wake Locks)不同(喚醒鎖的內(nèi)容在本章節(jié)后半部分),它不需要任何特殊的權(quán)限,系統(tǒng)會正確地 管理應(yīng)用之間的切換,且不必關(guān)心釋放資源的問題。

另外一種方法是在應(yīng)用的XML布局文件里,使用android:keepScreenOn屬性:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:keepScreenOn="true">
    ...
</RelativeLayout>

使用android:keepScreenOn="true"與使用FLAG_KEEP_SCRRE_ON等效。你可以選擇最適合你的應(yīng)用的方法。在Activity中通過代碼設(shè)置常亮標(biāo)識的優(yōu)點在于:你可以通過代碼動態(tài)清除這個標(biāo)示,從而使屏幕可以關(guān)閉。

Notes:除非你不再希望正在運行的應(yīng)用長時間點亮屏幕(例如:在一定時間無操作發(fā)生后,你想要將屏幕關(guān)閉),否則你是不需要清除FLAG_KEEP_SCRRE_ON 標(biāo)識的。WindowManager會在應(yīng)用進入后臺或者返回前臺時,正確管理屏幕的點亮或者關(guān)閉。但是如果你想要顯式地清除這一標(biāo)識,從而使得屏幕能夠關(guān)閉,可以使用getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)方法。

保持CPU運行

如果你需要在設(shè)備睡眠之前,保持CPU運行來完成一些工作,你可以使用PowerManager系統(tǒng)服務(wù)中的喚醒鎖功能。喚醒鎖允許應(yīng)用控制設(shè)備的電源狀態(tài)。

創(chuàng)建和保持喚醒鎖會對設(shè)備的電源壽命產(chǎn)生巨大影響。因此你應(yīng)該僅在你確實需要時使用喚醒鎖,且使用的時間應(yīng)該越短越好。如果想要在Activity中使用喚醒鎖就顯得沒有必要了。如上所述,可以在Activity中使用FLAG_KEEP_SCRRE_ON讓屏幕保持常亮。

使用喚醒鎖的一種合理情況可能是:一個后臺服務(wù)需要在屏幕關(guān)閉時利用喚醒鎖保持CPU運行。再次強調(diào),應(yīng)該盡可能規(guī)避使用該方法,因為它會影響到電池壽命。

不必使用喚醒鎖的情況

  1. 如果你的應(yīng)用正在執(zhí)行一個HTTP長連接的下載任務(wù),可以考慮使用DownloadManager。
  2. 如果你的應(yīng)用正在從一個外部服務(wù)器同步數(shù)據(jù),可以考慮創(chuàng)建一個SyncAdapter
  3. 如果你的應(yīng)用需要依賴于某些后臺服務(wù),可以考慮使用RepeatingAlarm或者Google Cloud Messaging,以此每隔特定的時間,將這些服務(wù)激活。

為了使用喚醒鎖,首先需要在應(yīng)用的Manifest清單文件中增加WAKE_LOCK權(quán)限:

<uses-permission android:name="android.permission.WAKE_LOCK" />

如果你的應(yīng)用包含一個BroadcastReceiver并使用Service來完成一些工作,你可以通過WakefulBroadcastReceiver管理你喚醒鎖。后續(xù)章節(jié)中將會提到,這是一種推薦的方法。如果你的應(yīng)用不滿足上述情況,可以使用下面的方法直接設(shè)置喚醒鎖:

PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE);
Wakelock wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
        "MyWakelockTag");
wakeLock.acquire();

可以調(diào)用wakelock.release()來釋放喚醒鎖。當(dāng)應(yīng)用使用完畢時,應(yīng)該釋放該喚醒鎖,以避免電量過度消耗。

使用WakefulBroadcastReceiver

你可以將BroadcastReceiver和Service結(jié)合使用,以此來管理后臺任務(wù)的生命周期。WakefulBroadcastReceiver是一種特殊的BroadcastReceiver,它專注于創(chuàng)建和管理應(yīng)用的PARTIAL_WAKE_LOCK。WakefulBroadcastReceiver會將任務(wù)交付給Service(一般會是一個IntentService),同時確保設(shè)備在此過程中不會進入睡眠狀態(tài)。如果在該過程當(dāng)中沒有保持住喚醒鎖,那么還沒等任務(wù)完成,設(shè)備就有可能進入睡眠狀態(tài)了。其結(jié)果就是:應(yīng)用可能會在未來的某一個時間節(jié)點才把任務(wù)完成,這顯然不是你所期望的。

要使用WakefulBroadcastReceiver,首先在Manifest文件添加一個標(biāo)簽:

<receiver android:name=".MyWakefulReceiver"></receiver>

下面的代碼通過startWakefulService()啟動MyIntentService。該方法和startService()類似,除了WakeflBroadcastReceiver會在Service啟動后將喚醒鎖保持住。傳遞給startWakefulService()的Intent會攜帶有一個Extra數(shù)據(jù),用來標(biāo)識喚醒鎖。

public class MyWakefulReceiver extends WakefulBroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {

        // Start the service, keeping the device awake while the service is
        // launching. This is the Intent to deliver to the service.
        Intent service = new Intent(context, MyIntentService.class);
        startWakefulService(context, service);
    }
}

當(dāng)Service結(jié)束之后,它會調(diào)用MyWakefulReceiver.completeWakefulIntent()來釋放喚醒鎖。completeWakefulIntent()方法中的Intent參數(shù)是和WakefulBroadcastReceiver傳遞進來的Intent參數(shù)一致的:

public class MyIntentService extends IntentService {
    public static final int NOTIFICATION_ID = 1;
    private NotificationManager mNotificationManager;
    NotificationCompat.Builder builder;
    public MyIntentService() {
        super("MyIntentService");
    }
    @Override
    protected void onHandleIntent(Intent intent) {
        Bundle extras = intent.getExtras();
        // Do the work that requires your app to keep the CPU running.
        // ...
        // Release the wake lock provided by the WakefulBroadcastReceiver.
        MyWakefulReceiver.completeWakefulIntent(intent);
    }
}


以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號