Katie McCormick | 7bdb3f6 | 2013-09-05 14:46:20 -0700 | [diff] [blame] | 1 | page.title=Keeping the Device Awake |
| 2 | |
| 3 | trainingnavtop=true |
| 4 | |
| 5 | @jd:body |
| 6 | |
| 7 | <div id="tb-wrapper"> |
| 8 | <div id="tb"> |
| 9 | |
| 10 | <!-- table of contents --> |
| 11 | <h2>This lesson teaches you to</h2> |
| 12 | <ol> |
| 13 | <li><a href="#screen">Keep the Screen On</a></li> |
| 14 | <li><a href="#cpu">Keep the CPU On</a></li> |
| 15 | </ol> |
| 16 | |
| 17 | <h2>Try it out</h2> |
| 18 | |
| 19 | <div class="download-box"> |
| 20 | <a href="{@docRoot}shareables/training/Scheduler.zip" |
| 21 | class="button">Download the sample</a> |
| 22 | <p class="filename">Scheduler.zip</p> |
| 23 | </div> |
| 24 | |
| 25 | </div> |
| 26 | </div> |
| 27 | |
| 28 | |
| 29 | <p>To avoid draining the battery, an Android device that is left idle quickly falls asleep. |
| 30 | However, there are times when an application needs to wake up the screen or the CPU |
| 31 | and keep it awake to complete some work.</p> |
| 32 | |
| 33 | <p>The approach you take depends on the needs of your app. However, a general rule of thumb |
| 34 | is that you should use the most lightweight approach possible for your app, to minimize your |
| 35 | app's impact on system resources. The following sections describe how to handle the cases |
| 36 | where the device's default sleep behavior is incompatible with the requirements of your app.</p> |
| 37 | |
| 38 | <h2 id="screen">Keep the Screen On</h2> |
| 39 | |
| 40 | <p>Certain apps need to keep the screen turned on, such as games or movie apps. The best |
| 41 | way to do this is to use the |
| 42 | {@link android.view.WindowManager.LayoutParams#FLAG_KEEP_SCREEN_ON FLAG_KEEP_SCREEN_ON} |
| 43 | in your activity (and only in an activity, never in a service or |
| 44 | other app component). For example:</p> |
| 45 | |
| 46 | <pre>public class MainActivity extends Activity { |
| 47 | @Override |
| 48 | protected void onCreate(Bundle savedInstanceState) { |
| 49 | super.onCreate(savedInstanceState); |
| 50 | setContentView(R.layout.activity_main); |
| 51 | <strong>getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);</strong> |
| 52 | }</pre> |
| 53 | |
| 54 | <p>The advantage of this approach is that unlike wake locks (discussed in <a href="#cpu"> |
| 55 | Keep the CPU On</a>), it doesn't require special permission, and the platform correctly |
| 56 | manages the user moving between applications, without your app needing to worry about |
| 57 | releasing unused resources.</p> |
| 58 | |
| 59 | <p>Another way to implement this is in your application's layout XML file, by using the |
| 60 | {@link android.R.attr#keepScreenOn android:keepScreenOn} attribute:</p> |
| 61 | |
| 62 | <pre><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" |
| 63 | android:layout_width="match_parent" |
| 64 | android:layout_height="match_parent" |
| 65 | <strong>android:keepScreenOn="true"></strong> |
| 66 | ... |
| 67 | </RelativeLayout></pre> |
| 68 | |
| 69 | <p>Using <code>android:keepScreenOn="true"</code> is equivalent to using |
| 70 | {@link android.view.WindowManager.LayoutParams#FLAG_KEEP_SCREEN_ON FLAG_KEEP_SCREEN_ON}. |
| 71 | You can use whichever approach is best for your app. The advantage of setting the flag |
| 72 | programmatically in your activity is that it gives you the option of programmatically |
| 73 | clearing the flag later and thereby allowing the screen to turn off.</p> |
| 74 | |
| 75 | <p class="note"><strong>Note:</strong> You don't need to clear the |
| 76 | {@link android.view.WindowManager.LayoutParams#FLAG_KEEP_SCREEN_ON FLAG_KEEP_SCREEN_ON} |
| 77 | flag unless you no longer want the screen to |
| 78 | stay on in your running application (for example, if you want the screen to time out |
| 79 | after a certain period of inactivity). The window manager takes care of |
| 80 | ensuring that the right things happen when the app goes into the background or returns to |
| 81 | the foreground. But if you want to explicitly clear the flag and thereby allow the screen to |
| 82 | turn off again, use {@link android.view.Window#clearFlags clearFlags()}: |
| 83 | {@code getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)}.</p> |
| 84 | |
| 85 | <h2 id="cpu">Keep the CPU On</h2> |
| 86 | |
| 87 | <div class="sidebox-wrapper"> |
| 88 | <div class="sidebox"> |
| 89 | <h2>Alternatives to using wake locks</h2> |
| 90 | |
| 91 | <ul> |
| 92 | |
| 93 | <li>If your app is performing long-running HTTP downloads, consider using |
| 94 | {@link android.app.DownloadManager}.</li> |
| 95 | |
| 96 | <li>If your app is synchronizing data from an external server, consider creating a |
| 97 | <a href="{@docRoot}training/sync-adapters/index.html">sync |
| 98 | adapter</a>.</li> |
| 99 | |
| 100 | <li>If your app relies on background services, consider using |
| 101 | <a href="{@docRoot}training/scheduling/alarms.html">repeating alarms</a> |
| 102 | or <a href="{@docRoot}google/gcm/index.html">Google Cloud Messaging</a> to trigger these |
| 103 | services at specific intervals.</li> |
| 104 | |
| 105 | </ul> |
| 106 | </div> |
| 107 | </div> |
| 108 | |
| 109 | |
| 110 | <p>If you need to keep the CPU running in order to complete some work before the device goes |
| 111 | to sleep, you can use a {@link android.os.PowerManager} system service feature called |
| 112 | wake locks. Wake locks allow your application to control the power state of the host device.</p> |
| 113 | |
| 114 | <p>Creating and holding wake locks can have a dramatic impact on the host device's battery |
| 115 | life. Thus you should use wake locks only when strictly necessary |
| 116 | and hold them for as short a time as possible. For example, you should never need to use a |
| 117 | wake lock in an activity. As described above, if you want |
| 118 | to keep the screen on in your activity, use |
| 119 | {@link android.view.WindowManager.LayoutParams#FLAG_KEEP_SCREEN_ON FLAG_KEEP_SCREEN_ON}.</p> |
| 120 | |
| 121 | |
| 122 | <p>One legitimate case for using a wake lock might be a background service |
| 123 | that needs to grab a wake lock to keep the CPU running to do work while the screen is off. |
| 124 | Again, though, this practice should be minimized because of its impact on battery life.</p> |
| 125 | |
| 126 | <p>To use a wake lock, the first step is to add the {@link android.Manifest.permission#WAKE_LOCK} |
| 127 | permission to your application's manifest file:</p> |
| 128 | |
| 129 | <pre><uses-permission android:name="android.permission.WAKE_LOCK" /></pre> |
| 130 | |
| 131 | <p>If your app includes a broadcast receiver that uses a service to do some |
| 132 | work, you can manage your wake lock through a |
| 133 | {@link android.support.v4.content.WakefulBroadcastReceiver}, as described in |
| 134 | <a href="#wakeful">Using a WakefulBroadcastReceiver</a>. This is the preferred approach. |
| 135 | If your app doesn't follow that pattern, here is how you set a wake lock |
| 136 | directly:</p> |
| 137 | |
| 138 | <pre> |
| 139 | PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE); |
| 140 | Wakelock wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, |
| 141 | "MyWakelockTag"); |
| 142 | wakeLock.acquire();</pre> |
| 143 | |
| 144 | <p>To release the wake lock, call |
| 145 | {@link android.os.PowerManager.WakeLock#release wakelock.release()}. This releases your |
| 146 | claim to the CPU. It's important to release a wake lock as soon as your app is finished |
| 147 | using it to avoid draining the battery.</p> |
| 148 | |
| 149 | <h3 id="wakeful">Using WakefulBroadcastReceiver</h3> |
| 150 | |
| 151 | <p>Using a broadcast receiver in conjunction with a service lets you manage the life cycle |
| 152 | of a background task.</p> |
| 153 | |
| 154 | <p>A {@link android.support.v4.content.WakefulBroadcastReceiver} is a special type of |
| 155 | broadcast receiver that takes care of |
| 156 | creating and managing a |
| 157 | {@link android.os.PowerManager#PARTIAL_WAKE_LOCK} for your app. A |
| 158 | {@link android.support.v4.content.WakefulBroadcastReceiver} |
| 159 | passes off the work to a {@link android.app.Service} |
| 160 | (typically an |
| 161 | {@link android.app.IntentService}), while ensuring that the device does not |
| 162 | go back to sleep in the transition. If you don't hold a wake lock while transitioning |
| 163 | the work to a service, you are effectively allowing the device to go back to sleep before |
| 164 | the work completes. The net result is that the app might not finish doing the work until |
| 165 | some arbitrary point in the future, which is not what you want.</p> |
| 166 | |
| 167 | <p>The first step in using a |
| 168 | {@link android.support.v4.content.WakefulBroadcastReceiver} is to add it to your |
| 169 | manifest, as with any other broadcast receiver:</p> |
| 170 | |
| 171 | <pre><receiver android:name=".MyWakefulReceiver"></receiver></pre> |
| 172 | |
| 173 | <p>The following code starts {@code MyIntentService} with the method |
| 174 | {@link android.support.v4.content.WakefulBroadcastReceiver#startWakefulService startWakefulService()}. |
| 175 | This method is comparable to {@link android.content.Context#startService startService()}, except that |
| 176 | the {@link android.support.v4.content.WakefulBroadcastReceiver} is holding a |
| 177 | wake lock when the service starts. The intent that is passed with |
| 178 | {@link android.support.v4.content.WakefulBroadcastReceiver#startWakefulService startWakefulService()} |
| 179 | holds an extra identifying the wake lock:</p> |
| 180 | |
| 181 | <pre>public class MyWakefulReceiver extends WakefulBroadcastReceiver { |
| 182 | |
| 183 | @Override |
| 184 | public void onReceive(Context context, Intent intent) { |
| 185 | |
| 186 | // Start the service, keeping the device awake while the service is |
| 187 | // launching. This is the Intent to deliver to the service. |
| 188 | Intent service = new Intent(context, MyIntentService.class); |
| 189 | startWakefulService(context, service); |
| 190 | } |
| 191 | }</pre> |
| 192 | |
| 193 | <p>When the service is finished, it calls |
| 194 | {@link android.support.v4.content.WakefulBroadcastReceiver#completeWakefulIntent MyWakefulReceiver.completeWakefulIntent()} |
| 195 | to release the wake lock. The |
| 196 | {@link android.support.v4.content.WakefulBroadcastReceiver#completeWakefulIntent completeWakefulIntent()} |
| 197 | method has as its parameter the same intent that was |
| 198 | passed in from the {@link android.support.v4.content.WakefulBroadcastReceiver}:</p> |
| 199 | <pre> |
| 200 | public class MyIntentService extends IntentService { |
| 201 | public static final int NOTIFICATION_ID = 1; |
| 202 | private NotificationManager mNotificationManager; |
| 203 | NotificationCompat.Builder builder; |
| 204 | public MyIntentService() { |
| 205 | super("MyIntentService"); |
| 206 | } |
| 207 | @Override |
| 208 | protected void onHandleIntent(Intent intent) { |
| 209 | Bundle extras = intent.getExtras(); |
| 210 | // Do the work that requires your app to keep the CPU running. |
| 211 | // ... |
| 212 | // Release the wake lock provided by the WakefulBroadcastReceiver. |
| 213 | MyWakefulReceiver.completeWakefulIntent(intent); |
| 214 | } |
| 215 | }</pre> |