Training—Managing Device Awake State

阅读:http://developer.android.com/training/scheduling/index.html

 

让屏幕常亮:

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

注意只能用在activity。也可以用个XML声明:

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

虽然你可以不手动清楚常亮的flag,但是官方也提供了这样的方法:

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

保持CPU运作就需要声明权限了:

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

你的service可能就需要用到CPU所以在下面写上:

代码:

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

To release the wake lock, call wakelock.release(). This releases your claim to the CPU. It's important to release a wake lock as soon as your app is finished using it to avoid draining the battery.

还有另外一种方法:用广播系统搭配service来实现:

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

记得最重要的:completeWakefulIntent,释放wake lock。

 


 

接下来讲一个比较好玩的东西:alarm。

它的特点:

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.

  1、定时执行任务;

  2、通过启动receiver启动service。

  3、完全脱离app去执行任务。

  

alarm有以下的参数:

  1、类型,下面会讲;2、触发时间,如果时间已经过去俺么立即触发;3、触发间隔;4、意图;

有几点需要注意:

  • 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() whenever possible. When you use setInexactRepeating(), Android synchronizes multiple inexact repeating alarms and fires them at the same time. This reduces the drain on the battery.
    • If your alarm's behavior is based on an interval (for example, your alarm fires once an hour) rather than a precise trigger time (for example, your alarm fires at 7 a.m. sharp and every 20 minutes after that), use an ELAPSED_REALTIME alarm type.

  尽可能不要呼唤系统,保持频率低一点以及进行有必要的行为。

   Use setInexactRepeating() instead of setRepeating():前者比较不精确但是省电,所以除了有必要,最好还是用前者。如果是通过时间间隔实现的,使用ELAPSED_REALTIME alarm type.

  有两种时钟类型:"elapsed real time" and "real time clock" 。前者是针对于机器启动之后的,适合用在时间间隔的alarm。后者使用精确的时间。

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.

  以上两者都有唤醒的类型,一种是就算屏幕关了也会提醒,一种是直到屏幕开了才提醒。

  类型在此!

  

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.
// Hopefully your alarm will have a lower frequency than this!
alarmMgr.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
        AlarmManager.INTERVAL_HALF_HOUR,
        AlarmManager.INTERVAL_HALF_HOUR, alarmIntent);

类似的代码,就跟上面所说的四个参数一样,一一对应,这个是半小时启动一次。

private AlarmManager alarmMgr;
private PendingIntent alarmIntent;
...
alarmMgr = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(context, AlarmReceiver.class);
alarmIntent = PendingIntent.getBroadcast(context, 0, intent, 0);

alarmMgr.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
        SystemClock.elapsedRealtime() +
        60 * 1000, alarmIntent);

类似的代码,一分钟后启动,不循环启动。

下面是RTC的例子,下午两点启动,并且每天循环一次:

// Set the alarm to start at approximately 2:00 p.m.
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.set(Calendar.HOUR_OF_DAY, 14);

// With setInexactRepeating(), you have to use one of the AlarmManager interval
// constants--in this case, AlarmManager.INTERVAL_DAY.
alarmMgr.setInexactRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(),
        AlarmManager.INTERVAL_DAY, alarmIntent);

下面这个是八点半启动,20分钟一次

private AlarmManager alarmMgr;
private PendingIntent alarmIntent;
...
alarmMgr = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(context, AlarmReceiver.class);
alarmIntent = PendingIntent.getBroadcast(context, 0, intent, 0);

// Set the alarm to start at 8:30 a.m.
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.set(Calendar.HOUR_OF_DAY, 8);
calendar.set(Calendar.MINUTE, 30);

// setRepeating() lets you specify a precise custom interval--in this case,
// 20 minutes.
alarmMgr.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(),
        1000 * 60 * 20, alarmIntent);

取消闹钟:

// If the alarm has been set, cancel it.
if (alarmMgr!= null) {
    alarmMgr.cancel(alarmIntent);
}

需要注意的是,一旦关机,闹钟就自动被取消了,如果每次开机都有效果那么就用下面的方法:

<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
public class SampleBootReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        if (intent.getAction().equals("android.intent.action.BOOT_COMPLETED")) {
            // Set the alarm here.
        }
    }
}
<receiver android:name=".SampleBootReceiver"
        android:enabled="false">
    <intent-filter>
        <action android:name="android.intent.action.BOOT_COMPLETED"></action>
    </intent-filter>
</receiver>

注意,这里有个属性 android:enabled="false"。这是为了receiver在没必要的时候被开机启动,要enable或者disable就用:

ComponentName receiver = new ComponentName(context, SampleBootReceiver.class);
PackageManager pm = context.getPackageManager();

pm.setComponentEnabledSetting(receiver,
        PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
        PackageManager.DONT_KILL_APP);

ComponentName receiver = new ComponentName(context, SampleBootReceiver.class);
PackageManager pm = context.getPackageManager();

pm.setComponentEnabledSetting(receiver,
        PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
        PackageManager.DONT_KILL_APP);

 

 

 

 

 

 

 

posted @ 2013-11-09 11:16  yutoulck  阅读(345)  评论(0编辑  收藏  举报