Android保持设备唤醒状态
来源:互联网 发布:最简单的游戏c编程 编辑:程序博客网 时间:2024/05/29 06:53
当Android设备空闲时,屏幕会变暗,然后关闭屏幕,最后会停止CPU的运行,这样可以防止电池电量掉的快。在休眠过程中自定义的Timer、Handler、Thread、Service等都会暂停。但有些时候我们需要改变Android系统默认的这种状态:比如玩游戏时我们需要保持屏幕常亮,比如一些下载操作不需要屏幕常亮但需要CPU一直运行直到任务完成。
- 保持屏幕常亮
- 保持cpu运行
- 直接使用唤醒锁
- 使用WakefulBroadcastReceiver
- WakefulBroadcastReceiver源码分析
- 采用定时重复的Service开启
保持屏幕常亮
游戏开发时,要保持游戏界面一直亮着。
常用方法:在Activity中使用FLAG_KEEP_SCREEN_ON 的Flag。
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); }}
这个方法的好处是不像唤醒锁(wake locks),需要一些特定的权限(permission)。并且能正确管理不同app之间的切换,不用担心无用资源的释放问题。
另一种方式:另一个方式是在布局文件中使用android:keepScreenOn属性。
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:keepScreenOn="true"> ...</LinearLayout>
android:keepScreenOn =”true“的作用和FLAG_KEEP_SCREEN_ON一样。第一种方式好处是你允许你在需要的地方关闭屏幕。
注意:一般不需要人为的去掉FLAG_KEEP_SCREEN_ON的flag,windowManager会管理好程序进入后台回到前台的的操作。如果确实需要手动清掉常亮的flag,使用getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
保持cpu运行
需要使用PowerManager这个系统服务的唤醒锁(wake locks)特征来保持CPU处于唤醒状态。
唤醒锁可划分为并识别四种用户唤醒锁:
注意:自 API 等级 17 开始,FULL_WAKE_LOCK 将被弃用。 应用应使用 FLAG_KEEP_SCREEN_ON。
第一步就是添加唤醒锁权限:
<uses-permission android:name="android.permission.WAKE_LOCK" />
直接使用唤醒锁
PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE);WakeLock wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,"MyWakelockTag");wakeLock.acquire();
注意:在不需要的时候release。
但推荐的方式是使用WakefulBroadcastReceiver:使用广播和Service(典型的IntentService)结合的方式可以让你很好地管理后台服务的生命周期。
WakefulBroadcastReceiver是BroadcastReceiver的一种特例。它会为你的APP创建和管理一个PARTIAL_WAKE_LOCK 类型的WakeLock。WakefulBroadcastReceiver把工作交接给service(通常是IntentService),并保证交接过程中设备不会进入休眠状态。如果不持有WakeLock,设备很容易在任务未执行完前休眠。
使用WakefulBroadcastReceiver
第一步就是在Manifest中注册: java<receiver android:name=".MyWakefulReceiver"></receiver>
使用startWakefulService()方法来启动服务,与startService()相比,在启动服务的同时,并启用了唤醒锁。
@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()来释放唤醒锁。
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); }}
WakefulBroadcastReceiver源码分析
public static ComponentName startWakefulService(Context context, Intent intent) { synchronized (mActiveWakeLocks) { int id = mNextId; mNextId++; if (mNextId <= 0) { mNextId = 1; } intent.putExtra(EXTRA_WAKE_LOCK_ID, id); ComponentName comp = context.startService(intent); if (comp == null) { return null; } PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE); PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "wake:" + comp.flattenToShortString()); wl.setReferenceCounted(false); wl.acquire(60*1000); mActiveWakeLocks.put(id, wl); return comp; } }
它里面启动了一个60秒的锁,在需要释放的时候调用completeWakefulIntent(Intent intent)方法
public static boolean completeWakefulIntent(Intent intent) { final int id = intent.getIntExtra(EXTRA_WAKE_LOCK_ID, 0); if (id == 0) { return false; } synchronized (mActiveWakeLocks) { PowerManager.WakeLock wl = mActiveWakeLocks.get(id); if (wl != null) { wl.release(); mActiveWakeLocks.remove(id); return true; } // We return true whether or not we actually found the wake lock // the return code is defined to indicate whether the Intent contained // an identifier for a wake lock that it was supposed to match. // We just log a warning here if there is no wake lock found, which could // happen for example if this function is called twice on the same // intent or the process is killed and restarted before processing the intent. Log.w("WakefulBroadcastReceiver", "No active wake lock id #" + id); return true; } }
采用定时重复的Service开启
利用Android自带的定时器AlarmManager实现:
Intent intent = new Intent(mContext, ServiceTest.class);PendingIntent pi = PendingIntent.getService(mContext, 1, intent, 0);AlarmManager alarm = (AlarmManager) getSystemService(Service.ALARM_SERVICE);if(alarm != null){ alarm.cancel(pi); // 闹钟在系统睡眠状态下会唤醒系统并执行提示功能 alarm.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + 1000, 2000, pi);// 确切的时间闹钟//alarm.setExact(…); //alarm.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), pi);}
该定时器可以启动Service服务、发送广播、跳转Activity,并且会在系统睡眠状态下唤醒系统。所以该方法不用获取电源锁和释放电源锁。
注意:在19以上版本,setRepeating中设置的频繁只是建议值(6.0 的源码中最小值是60s),如果要精确一些的用setWindow或者setExact。
总结
- 关键逻辑的执行过程,就需要Wake Lock来保护,如断线重连重新登陆。
- 休眠的情况下唤醒cpu来执行任务用AlarmManager,如推送消息的获取。
最后附一张微信的图
- Android保持设备唤醒状态
- 保持android设备唤醒状态
- Android保持设备唤醒状态
- Android保持设备为唤醒状态
- android之保持设备唤醒
- android 保持屏幕唤醒状态
- Android应用程序 --- WakeLock 保持后台唤醒状态
- Android应用程序 --- WakeLock 保持后台唤醒状态
- Android保持屏幕常亮唤醒状态
- Android应用程序 --- WakeLock 保持后台唤醒状态
- Android应用程序 --- WakeLock 保持后台唤醒状态
- Android应用程序---WakeLock保持后台唤醒状态
- Android应用程序 --- WakeLock 保持后台唤醒状态
- Android保持屏幕常亮唤醒状态
- Android应用程序 --- WakeLock 保持后台唤醒状态
- 保持设备唤醒
- 保持设备唤醒
- 保持设备唤醒
- C# Get方式请求Http
- POJ 3498 最大流
- 【转】Linux系统下为WPS添加字体,实现WPS输入中文
- 安卓 解析xml
- DataTable转JSON到前台
- Android保持设备唤醒状态
- 【书山有路】Python基础教程 第2章
- CPU,内存,硬盘,指令之间的关系
- 剖析虚函数
- ueditor:使用笔记:
- Mproxy项目实录第1天
- mysqlbinlog恢复增量备份数据
- [LeetCode] 89. Gray Code
- PAT A1098. Insertion or Heap Sort (25)