码迷,mamicode.com
首页 > 移动开发 > 详细

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

时间:2015-09-15 20:02:53      阅读:259      评论:0      收藏:0      [点我收藏+]

标签:

这几个月一直在学习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服务或者其他程序组件中使用),例如:

@Override

protectedvoid( savedInstanceState superonCreatesavedInstanceState);

(..);

().(..);

  }

...

使用这种方式的优点是,它不像唤醒锁(将在下面的"保持CPU开启"中讨论),它不需要请求特别的权限,并且系统能够正确的管理用户在不同应用程序间的切换,你的程序无需担心释放不使用的资源。

另外一种实现的方式是在你的程序的布局文件中,使用android:keepScreenOn属性:

=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() 方法。

.

 

保持CPU运转(Keep the CPU On)

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

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

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

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

= />

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

powerManager PowerManager getSystemServicePOWER_SERVICE);

wakeLock powerManagernewWakeLockPowerManagerPARTIAL_WAKE_LOCK"MyWakelockTag");

wakeLock.acquire();

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

 

使用WakefulBroadcastReceiver(Use WakefulBroadcastReceiver)

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

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

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

=></receiver> 

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

 

@Override

publicvoid( context intent

        // Start the service, keeping the device awake while the service is

        // launching. This is the Intent to deliver to the service.

Intent=newIntentcontext .);

(,);

}

当服务完成时,它会调用 MyWakefulReceiver.completeWakefulIntent() 方法来释放唤醒锁,这个 compleWakefulIntent() 方法有一个与在 WakefulBroadcastReceiver 中传入的相同的Intent作为参数。

publicstaticfinalint=1;

privateNotificationManager;

NotificationCompatBuilder;

publicMyIntentService super"MyIntentService");

}

@Override

protectedvoid( intent Bundle=.();

        // Do the work that requires your app to keep the CPU running.

        // ...

        // Release the wake lock provided by the WakefulBroadcastReceiver.

MyWakefulReceivercompleteWakefulIntentintent);

}

}

 

 

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

Alarms (based on the AlarmManager class) give you a way to perform time-based operations outside the lifetime of your application. For example, you could use an alarm to initiate a long-running operation, such as starting a service once a day to download a weather forecast.

Alarms have these characteristics:

  • They let you fire Intents at set times and/or intervals.
  • You can use them in conjunction with broadcast receivers to start services and perform other operations.
  • They operate outside of your application, so you can use them to trigger events or actions even when your app is not running, and even if the device itself is asleep.
  • They help you to minimize your app‘s resource requirements. You can schedule operations without relying on timers or continuously running background services.

Note: For timing operations that are guaranteed to occur during the lifetime of your application, instead consider using the Handler class in conjunction with Timer and Thread. This approach gives Android better control over system resources.

Understand the Trade-offs

 

A repeating alarm is a relatively simple mechanism with limited flexibility. It may not be the best choice for your app, particularly if you need to trigger network operations. A poorly designed alarm can cause battery drain and put a significant load on servers.

A common scenario for triggering an operation outside the lifetime of your app is syncing data with a server. This is a case where you might be tempted to use a repeating alarm. But if you own the server that is hosting your app‘s data, using Google Cloud Messaging (GCM) in conjunction with sync adapter is a better solution than AlarmManager. A sync adapter gives you all the same scheduling options as AlarmManager, but it offers you significantly more flexibility. For example, a sync could be based on a "new data" message from the server/device (see Running a Sync Adapter for details), the user‘s activity (or inactivity), the time of day, and so on. See the linked videos at the top of this page for a detailed discussion of when and how to use GCM and sync adapter.

Best practices

Every choice you make in designing your repeating alarm can have consequences in how your app uses (or abuses) system resources. For example, imagine a popular app that syncs with a server. If the sync operation is based on clock time and every instance of the app syncs at 11:00 p.m., the load on the server could result in high latency or even "denial of service." Follow these best practices in using alarms:

  • Add randomness (jitter) to any network requests that trigger as a result of a repeating alarm:
    • Do any local work when the alarm triggers. "Local work" means anything that doesn‘t hit a server or require the data from the server.
    • At the same time, schedule the alarm that contains the network requests to fire at some random period of time.
  • Keep your alarm frequency to a minimum.
  • Don‘t wake up the device unnecessarily (this behavior is determined by the alarm type, as described in Choose an alarm type).
  • Don‘t make your alarm‘s trigger time any more precise than it has to be. Use setInexactRepeating() instead of setRepeating(). When you use setInexactRepeating(), Android synchronizes repeating alarms from multiple apps and fires them at the same time. This reduces the total number of times the system must wake the device, thus reducing drain on the battery. As of Android 4.4 (API Level 19), all repeating alarms are inexact. Note that while setInexactRepeating() is an improvement over setRepeating(), it can still overwhelm a server if every instance of an app hits the server around the same time. Therefore, for network requests, add some randomness to your alarms, as discussed above.
  • Avoid basing your alarm on clock time if possible. Repeating alarms that are based on a precise trigger time don‘t scale well. Use ELAPSED_REALTIME if you can. The different alarm types are described in more detail in the following section.

Set a Repeating Alarm

 

As described above, repeating alarms are a good choice for scheduling regular events or data lookups. A repeating alarm has the following characteristics:

  • A alarm type. For more discussion, see Choose an alarm type.
  • A trigger time. If the trigger time you specify is in the past, the alarm triggers immediately.
  • The alarm‘s interval. For example, once a day, every hour, every 5 seconds, and so on.
  • A pending intent that fires when the alarm is triggered. When you set a second alarm that uses the same pending intent, it replaces the original alarm.

Choose an alarm type

One of the first considerations in using a repeating alarm is what its type should be.

There are two general clock types for alarms: "elapsed real time" and "real time clock" (RTC). Elapsed real time uses the "time since system boot" as a reference, and real time clock uses UTC (wall clock) time. This means that elapsed real time is suited to setting an alarm based on the passage of time (for example, an alarm that fires every 30 seconds) since it isn‘t affected by time zone/locale. The real time clock type is better suited for alarms that are dependent on current locale.

Both types have a "wakeup" version, which says to wake up the device‘s CPU if the screen is off. This ensures that the alarm will fire at the scheduled time. This is useful if your app has a time dependency—for example, if it has a limited window to perform a particular operation. If you don‘t use the wakeup version of your alarm type, then all the repeating alarms will fire when your device is next awake.

If you simply need your alarm to fire at a particular interval (for example, every half hour), use one of the elapsed real time types. In general, this is the better choice.

If you need your alarm to fire at a particular time of day, then choose one of the clock-based real time clock types. Note, however, that this approach can have some drawbacks—the app may not translate well to other locales, and if the user changes the device‘s time setting, it could cause unexpected behavior in your app. Using a real time clock alarm type also does not scale well, as discussed above. We recommend that you use a "elapsed real time" alarm if you can.

Here is the list of types:

  • ELAPSED_REALTIME—Fires the pending intent based on the amount of time since the device was booted, but doesn‘t wake up the device. The elapsed time includes any time during which the device was asleep.
  • ELAPSED_REALTIME_WAKEUP—Wakes up the device and fires the pending intent after the specified length of time has elapsed since device boot.
  • RTC—Fires the pending intent at the specified time but does not wake up the device.
  • RTC_WAKEUP—Wakes up the device to fire the pending intent at the specified time.

ELAPSED_REALTIME_WAKEUP examples

Here are some examples of using ELAPSED_REALTIME_WAKEUP.

Wake up the device to fire the alarm in 30 minutes, and every 30 minutes after that:

.(.,

AlarmManagerINTERVAL_HALF_HOUR        AlarmManager.INTERVAL_HALF_HOUR, alarmIntent);

Wake up the device to fire a one-time (non-repeating) alarm in one minute:

alarmMgr;

alarmIntent;

=().(.);

intent (,AlarmReceiverclass);

=PendingIntentgetBroadcastcontext ,,0);

 

.(.,

SystemClockelapsedRealtime         60 * 1000, alarmIntent);

RTC examples

Here are some examples of using RTC_WAKEUP.

Wake up the device to fire the alarm at approximately 2:00 p.m., and repeat once a day at the same time:

calendar .();

.(.());

.(.,14);

 

.(.,.(),

        AlarmManager.INTERVAL_DAY, alarmIntent);

Wake up the device to fire the alarm at precisely 8:30 a.m., and every 20 minutes thereafter:

alarmMgr;

alarmIntent;

=().(.);

intent (,AlarmReceiverclass);

=PendingIntentgetBroadcastcontext ,,0);

 

calendar .();

.(.());

.(.,8);

.(.,30);

 

.(.,.(),

        1000 * 60 * 20, alarmIntent);

Decide how precise your alarm needs to be

As described above, choosing the alarm type is often the first step in creating an alarm. A further distinction is how precise you need your alarm to be. For most apps, setInexactRepeating() is the right choice. When you use this method, Android synchronizes multiple inexact repeating alarms and fires them at the same time. This reduces the drain on the battery.

For the rare app that has rigid time requirements—for example, the alarm needs to fire precisely at 8:30 a.m., and every hour on the hour thereafter—use setRepeating(). But you should avoid using exact alarms if possible.

With setInexactRepeating(), you can‘t specify a custom interval the way you can with setRepeating(). You have to use one of the interval constants, such as INTERVAL_FIFTEEN_MINUTES, INTERVAL_DAY, and so on. See AlarmManager for the complete list.

Cancel an Alarm

 

Depending on your app, you may want to include the ability to cancel the alarm. To cancel an alarm, call cancel() on the Alarm Manager, passing in the PendingIntent you no longer want to fire. For example:

alarmMgr ){

.();

}

Start an Alarm When the Device Boots

 

By default, all alarms are canceled when a device shuts down. To prevent this from happening, you can design your application to automatically restart a repeating alarm if the user reboots the device. This ensures that the AlarmManager will continue doing its task without the user needing to manually restart the alarm.

Here are the steps:

  1. Set the RECEIVE_BOOT_COMPLETED permission in your application‘s manifest. This allows your app to receive the ACTION_BOOT_COMPLETED that is broadcast after the system finishes booting (this only works if the app has already been launched by the user at least once): <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
  2. Implement a BroadcastReceiver to receive the broadcast:
  3.         onReceiveContext,Intent){
  4.         intentgetActionequals"android.intent.action.BOOT_COMPLETED"             // Set the alarm here.
  5.             }
  6. Add the receiver to your app‘s manifest file with an intent filter that filters on the ACTION_BOOT_COMPLETED action: <receiver android:name=".SampleBootReceiver"
  7.         =>
  8.     <intent-filter>
  9.         =></action>
  10.     </intent-filter>
  11. </receiver>
    Notice that in the manifest, the boot receiver is set to android:enabled="false". This means that the receiver will not be called unless the application explicitly enables it. This prevents the boot receiver from being called unnecessarily. You can enable a receiver (for example, if the user sets an alarm) as follows:
    ComponentName receiver = new ComponentName(context, SampleBootReceiver.class);
  12. PackageManager=.();
  13. pmsetComponentEnabledSettingreceiver        .,
  14.         PackageManager.DONT_KILL_APP);
    Once you enable the receiver this way, it will stay enabled, even if the user reboots the device. In other words, programmatically enabling the receiver overrides the manifest setting, even across reboots. The receiver will stay enabled until your app disables it. You can disable a receiver (for example, if the user cancels an alarm) as follows:
    ComponentName receiver = new ComponentName(context, SampleBootReceiver.class);
  15. PackageManager=.();
  16. pmsetComponentEnabledSettingreceiver        .,
  17.         .);

 

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

标签:

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

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!