Android官方文章翻译之管理设备苏醒状态(Managing Device Awake State)(一)

这几个月一直在学习iOS开发,把Android放在一旁耽搁了很久,是时候温故而知新了。

说点篇外话,这几天在看Developer的官方文档,关于Material Design又了解了一下。

Material早在2014年的GoogleIO大会就已经被谷歌推出了,但是市场上采用这种新的设计方案的APP确是少之又少,国外倒是跟进的很快,国内几乎没有任何进展,纵观国内各大公司的移动APP,很少会“与时俱进”的采用Google推出的新系统的设计方案。

不过这原因由来已久了,因为安卓系统的版本分布太过零散,各大手机品牌也都各自为营,采用自家定制的UI界面,这就导致了如果你想使用Google的设计来重新设计你的APP,会导致你的程序,从图标到用户界面,可能会与用户的手机格格不入,所以大部分公司的APP都采用了“通用”的设计,一般主色调都是自家品牌色调,比如大众点评的橘黄色色调,微信,美团等的蓝色调。

所以,对于程序员来说,应用新技术到程序中,往往很艰难。如果想学习新技术并应用,只能自己写小DEMO了,如果你很懒,那可能到目前为止,都没写过Material Design设计风格的程序吧!我会觉得这是一个遗憾,因为这样久而久之,你会变得已经跟不上Android的进化了,很多API的变化会让你措手不及。其实我自己也属于遗憾行列,自从在学习iOS后,就很少关注了。最近重新复习时,发现,系统已经多了很多让你看着很茫然的API方法和技巧,很多方法名或者说技巧,设计模式等跟iOS还挺像的,比如Material Design中现在多了叫tint color的颜色属性,用来设置状态栏的颜色等,这个iOS中的Navigation Bar中的tint color是类似的。

总之一句话,不要忘记和停止了学习,因为我们是搞技术的。^_^

。。。感觉再不进入正题会跑偏,先不说了吧,写今天的内容了。

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////

当你的设备处于闲置状态时,它将首先屏幕变暗,然后关闭屏蔽(即黑屏,你得按电源键等重新电量它),最终将关闭手机的CPU,这么做的目的是阻止设备的电池快速的耗尽,然而很多时候,你的程序可能会请求一些不太寻常的行为,需要保持你的手机“运转”着,不黑屏。

1.诸如游戏或者视频类的程序会想要保持屏幕常亮。

2.其他的程序可能不需要屏幕常亮着,但是它们仍然需要保持CPU为它们工作直到一个紧急的任务完成。

本节课描述当需要时如何保持设备处于唤醒状态而不必耗尽电池。

课程:

1.保持设备处于唤醒状态

学习如何保持屏幕或CPU处于唤醒状态,并最大限度的减少对电池寿命的影响。

2.执行重复报警(提醒)

学习如何使用重复提醒来执行处于应用程序生命周期之外的操作,甚至程序没有运行或设备处于休眠状态。

1.保持设备处于唤醒状态(Keeping the Device Awake)

为了避免耗尽电池,安卓设备会让自身迅速闲置,处于睡眠状态。然而,会有场景需要程序唤醒屏幕或CPU,然后保持这种状态直到完成某些任务。

你所采用的方法应依据你自身程序的需要,然而,一般的经验法则是这样的,你应该使用尽可能轻量的方法来使你的程序最小化消耗系统资源,接下来的章节描述如何来处理这样一种情况,即你的设备的默认睡眠行为与你的程序的需要(即需要保持屏幕唤醒,需要CPU为你工作的这种需要)的不相容性。

保持屏幕常亮(Keep the Screen On)

某些程序需要保持屏幕常亮,比如游戏或者播放器类程序,最好的方式是在你的Activity中使用FLAG_KEEP_SCREEN_ON(只能在Activity中设置,不要在Service服务或者其他程序组件中使用),例如:

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

使用这种方式的优点是,它不像唤醒锁(将在下面的"保持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 是等价的,你可以使用任何一种最适合你的程序的方式来设定。在你的Activity中设置flag的编程方式的优点是它可以让你在稍后选择性的清除这个flag从而使得允许屏幕关闭的行为。

注意:你无需清除 FLAG_KEEP_SCREEN_ON 这个flag,除非你不再想让屏幕保持在你的运行中的程序上(比如,如果你想在闲置一段之后让屏幕超时)。窗口管理器将关心这些事宜,并确保正确的事情发生在诸如当程序进入后台或者恢复到前台时。但是如果你想直接清除这个flag从而运行屏幕再次自动关闭,请使用 clearFlags() 方法。

getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON). 

保持CPU运转(Keep the CPU On)

如果为了在设备进入睡眠之前完成某些工作,你必须保持CPU处于运转状态,你可以使用 PowerManager 系统服务功能来唤醒锁。唤醒锁运行你的程序控制主设备的电源状态。

创建并保持一个唤醒锁将对主机设备的电池寿命产生显著的影响,因此你应该在当严格的需要时才去使用唤醒锁,然后在尽可能短的时间内保持它。例如,你应该从不在一个Activity中使用一个唤醒锁,正如上面所描述的,如果你想在你的Activity上保持屏幕常亮,应该使用 FLAG_KEEP_SCREEN_ON 。

一个合理的使用一个唤醒锁的场景可能是在一个后台服务中,这个服务需要持有这个唤醒锁,确保在屏幕关闭时保持CPU处于运转工作状态。再次强调,即便如此,由于其对电池寿命的影响这种做法应该尽量减少。

为了使用一个唤醒锁,第一步便是添加 WAKE_LOCK 权限到你的程序的manifest文件中。

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

如果你的程序包含一个广播接收器并且它使用一个服务来执行某些工作,你应该通过一个 WakefulBroadcastReceiver 来管理你的唤醒锁,下面将会描述这个方式的具体使用方法。这是首选的一种方式。如果你的程序不遵循这种模式,下面是直接设置一个唤醒锁的方法:

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

调用 wakelock.release() 方法来释放唤醒锁,这个方法释放了你对CPU的持有需求。一旦你的程序关闭时,释放这个唤醒锁是非常重要的一步操作,这将避免你的程序对电池的消耗。

使用WakefulBroadcastReceiver(Use WakefulBroadcastReceiver)

使用一个广播接收器结合一个服务使得你可以管理一个后台任务的生命周期。

一个 WakefulBroadcastReceiver 是一种特殊类型的广播接收器,它负责为你的程序创建和管理一个 PARTIAL_WAKE_LOCK 。一个 WakefulBroadcastReceiver 传递工作给一个服务(典型的是一个IntentService),同时确保设备不会在传递过程休眠。如果你在传递一个任务给服务时没有保持一个唤醒锁,你实际上是直接允许了在任务完成之前,设备可以休眠。最终的结果是应用程序无法完成任务,一直到未来的某个任意的时间点,这不是你想要的。

使用 WakefulBroadcastReceiver 的第一步是将其添加到你的manifest中,就和任何其他的广播接收器一样:

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

下面的代码通过 startWakefulService() 启动 MyIntentService,这个方法与 startSevice() 类似,除了 WakefulBroadcastReceiver 会在服务启动时持有一个唤醒锁之外。传入 startWakefulService() 方法的Intent持有一个额外的信息标识这个唤醒锁。

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() 方法来释放唤醒锁,这个 compleWakefulIntent() 方法有一个与在 WakefulBroadcastReceiver 中传入的相同的Intent作为参数。 

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

2.执行重复报警(提醒)(Scheduling Repeating Alarms)

放到下一篇中。Android官方文章翻译之管理设备苏醒状态(Managing Device Awake State)(二)

原文地址:https://www.cnblogs.com/emmet7life/p/4811101.html