保存设备唤醒
本篇是https://developer.android.com/training/scheduling/wakelock.html#screen的译文,仅供学习和参考。
为了避免电池耗尽,android设备进入idle状态后就会快速的进入睡眠状态(idle状态的定义参考链接第一行定义)。然而,有些时候应用需要唤醒屏幕或者CPU来完成一些工作。
采取的方法视你的app需要而定,通常的经验法则是你应该用最轻量方法来降低你的应用对系统资源的影响。下面部分介绍了如何处理设备默认的睡眠行为和你的应用需求不兼容时的例子。
保持屏幕开启
像游戏或视频类应用需要屏幕保持开启,实现这个最好的方法就是在你的Activity(只限Activity,其他组件不支持)中设定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);
}
这个方法的好处不像wake locks(后面保持CPU运行章节会涉及)需要特定的权限,也不需要平台管理用户在应用间的迁移,更不需要你的应用释放未使用的资源。
另一种方法是在布局文件中使用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_SCREEN_ON标识效果是一样的。具体使用哪种依你应用需要而定。但相比较而言,设定 FLAG_KEEP_SCREEN_ON标识允许应用在稍后不再需要屏幕开启时编程清除这个标识以关闭屏幕(清除标识的方法getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON))。
保持CPU允许
如果在设备进入睡眠前你需要CPU运行来完成一些工作,你能使用系统服务PowerManager来调用wake locks。 wake locks允许你的应用控制主机设备的电源状态。
创建和持有wake lock对你的主机设备的电量有严重影响,所以你仅限严格需要的情况下使用wake locks并且持有wake locks尽可能短的时间。比如,你绝不可在Activity中使用wake lock,就像上面章节描述的在你的Acitiviyt中使用FLAG_KEEP_SCREEN_ON。
一个使用wake lock的正当例子可能就是一个后台Service在灭屏时需要获取wake lock来保持CPU运行并让CPU去做一些事情。然而,尽管如此,因为wake lock对电池寿命的影响这种做法应该最小化。
为了使用wake lock, 第一步就是在你的应用manifestf文件中添加WAKE_LOCK权限:
<uses-permission android:name="android.permission.WAKE_LOCK" />
如果你的应用包含了broadcast receiver,并且该broadcast receiver随后使用Service做一些事情,建议你使用WakefulBroadcastReceiver来管理你的wake lock,使用方法参见使用WakefulBroadcastReceiver章节。这是最推荐的方法,但是如果你不参考这个做法,下面是提供给你如何设置wake lock的做法:
PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE);
WakeLock wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
"MyWakelockTag");
wakeLock.acquire();
释放wake lock,调用wakelock.release().这个方法释放你申请的CPU。只要你的应用不再需要wake lock时释放它对于避免电池耗尽是很重要的。
使用WakefulBroadcastReceiver
BroadcastReceiver结合Service的使用可以让你管理后台任务的生命周期。
WakefulBroadcastReceiver是一个特别的broadcast receiver ,它负责创建和管理PARTIAL_WAKE_LOCK,将工作传递给服务(典型的是IntentService),并且确保设备不会在传递过程中使设备回到睡眠状态。如果在将工作传递给Service时不持有wake lock,则在Service完成工作之前,您可以有效地让设备返回睡眠状态,最终的结果是:应用程序可能在将来某个随意的时间点前没有完成需要完成的工作,这显然并不是你想要的。
使用WakefulBroadcastReceiver的第一步是将一个自定义子类添加到manifest文件中:
<receiver android:name=".MyWakefulReceiver"></receiver>
下面的代码是调用startWakefulService()启动MyIntentService,这个方法跟startService是类似的,除了WakefulBroadcastReceiver在服务启动前会持有wake lock,并且wake lock的id会传递保存在Intent的Extra中。
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);
}
}
当服务完成时,调用MyWakefulReceiver.completeWakefulIntent() 来释放wake lock, 该方法有个Intent参数,该Intent就是WakefulBroadcastReceiver传递过来的。
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);
}
}