Android 管理设备唤醒状态

1,216 阅读3分钟

1.概述

当 Android 设备空闲时,它会首先调暗屏幕,然后关闭屏幕,最终关闭 CPU。这可以防止设备的电池电量快速耗尽。不过,有时您的应用可能需要采取不同的行为:

  • 游戏或电影应用等应用可能需要使屏幕保持开启状态。
  • 其他应用可能不需要屏幕始终处于开启状态,但可能需要 CPU 持续运行,直到某项关键操作完成。

2.保持屏幕开启状态

  • FLAG_KEEP_SCREEN_ON
    class MainActivity : Activity() {

        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_main)
            window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
        }
    }
  • 在应用的布局 XML 文件中,使用 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>

上述两种方式的效果是一样的。如果需要清除状态,请调用getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)。

  • PowerManager

一.添加权限

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

二.获取PowerManager

val pm = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                pm = ctx.getSystemService(PowerManager::class.java)
            } else {
                pm = ctx.getSystemService(Context.POWER_SERVICE)?.let {
                    it as PowerManager
                }
            }   

三.创建WakeLock唤醒屏幕

  val wakeLock = pm?.newWakeLock(
                PowerManager.ACQUIRE_CAUSES_WAKEUP or PowerManager.SCREEN_BRIGHT_WAKE_LOCK,
                "wakeUp:screen")
  wakeLock?.acquire(5 * 1000L)//5秒后释放唤醒锁
  
  • WakefulBroadcastReceiver(AndroidX已移除)

特殊类型的广播接收器,负责为应用创建和管理 PARTIAL_WAKE_LOCK。

一.创建广播接收器

    class MyWakefulReceiver : WakefulBroadcastReceiver() {

        override fun onReceive(context: Context, intent: Intent) {

            Intent(context, MyIntentService::class.java).also { service ->
            
                //启动服务进行业务逻辑处理,在任务处理完之前,设备不会进入休眠状态
                WakefulBroadcastReceiver.startWakefulService(context, service)
            }
        }
    }

二.在Manifest中添加

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

三.释放


    class MyIntentService : IntentService("MyIntentService") {


        override fun onHandleIntent(intent: Intent) {
            val extras: Bundle = intent.extras
            //进行业务处理
            MyWakefulReceiver.completeWakefulIntent(intent)//完成后释放
        }
    }
    

3.保持CPU运行状态

  • AlarmManager

闹钟的类型:

  • ELAPSED_REALTIME - 基于自设备启动以来所经过的时间触发待定 intent,但不会唤醒设备。经过时间包括设备处于休眠状态期间的任何时间。
  • ELAPSED_REALTIME_WAKEUP - 唤醒设备,并在自设备启动以来特定时间过去之后触发待定 intent。
  • RTC - 在指定的时间触发待定 intent,但不会唤醒设备。
  • RTC_WAKEUP - 唤醒设备以在指定的时间触发待定 intent。

创建闹钟广播接收器

class AlarmReceiver: BroadcastReceiver() {
        override fun onReceive(context: Context?, intent: Intent?) {
            //do things
        }

    }

创建一次性闹钟

val alarmIntent = Intent(application, AlarmReceiver::class.java).let {
            intent -> 
            //如果需要传输数据可通过intent
            PendingIntent.getBroadcast(application,0,intent,0)
        }
    alarmIntent
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        alarm?.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP,
        SystemClock.elapsedRealtime()+delayTime,
        alarmIntent)
}else{
        alarm?.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
        SystemClock.elapsedRealtime()+delayTime,
        alarmIntent)
}

创建重复性闹钟

val alarmIntent = Intent(application, AlarmReceiver::class.java).let {
                intent -> PendingIntent.getBroadcast(application,0,intent,0)
        }
//非精确性重复性闹钟        
alarm?.setInexactRepeating(AlarmManager.RTC_WAKEUP,
                          SystemClock.elapsedRealtime()+AlarmManager.INTERVAL_HALF_HOUR,
                          AlarmManager.INTERVAL_HALF_HOUR,//每隔半个小时触发一次
                          alarmIntent)
//精确性重复闹钟                          
 alarm?.setRepeating(
            AlarmManager.RTC_WAKEUP,
            SystemClock.elapsedRealtime() + delayTime,
            AlarmManager.INTERVAL_HALF_HOUR,
            alarmIntent
        )

对于大多数应用来说,setInexactRepeating() 是合适的选择。因为Android 会同步多个不精确的重复闹钟,并同时触发它们。这样可以减少耗电量。 对于具有严格时间要求的应用,请使用 setRepeating()。不过应尽量避免使用精确的闹钟。

在设备重启时重新启动闹钟

默认情况下,当设备关机时,所有闹钟都会被取消。为了防止出现这种情况,您可以将应用设计为在用户重启设备时,自动重新启动重复闹钟。这样可以确保 AlarmManager 继续执行其任务,而无需用户手动重新启动闹钟。

  • 在Manifest中添加权限
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>

用户必须启动过应用一次,否则无效

  • 创建BroadcastReceiver接收启动广播
 class SampleBootReceiver : BroadcastReceiver() {

    override fun onReceive(context: Context, intent: Intent) {
        if (intent.action == "android.intent.action.BOOT_COMPLETED") {
            // 重新设置闹钟
        }
    }
}
  • 在Manifest中添加receiver
<receiver android:name=".SampleBootReceiver"
            android:enabled="false">
        <intent-filter>
            <action android:name="android.intent.action.BOOT_COMPLETED"></action>
        </intent-filter>
    </receiver>
  • 启用广播接收器
 val receiver = ComponentName(context, SampleBootReceiver::class.java)

    context.packageManager.setComponentEnabledSetting(
            receiver,
            PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
            PackageManager.DONT_KILL_APP
    )
    
  • 停用广播接收器
val receiver = ComponentName(context, SampleBootReceiver::class.java)

    context.packageManager.setComponentEnabledSetting(
            receiver,
            PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
            PackageManager.DONT_KILL_APP
    )