安卓电量优化之WakeLock锁机制全面解析

一、WakeLock概述

wakelock是一种锁的机制,只要有应用拿着这个锁,CPU就无法进入休眠状态,一直处于工作状态。比如,手机屏幕在屏幕关闭的时候,有些应用依然可以唤醒屏幕提示用户消息,这里就是用到了wakelock锁机制,虽然手机屏幕关闭了,但是这些应用依然在运行着。手机耗电的问题,大部分是开发人员没有正确使用这个锁,成为"待机杀手"。

Android手机有两个处理器,一个叫Application Processor(AP),一个叫Baseband Processor(BP)。AP是ARM架构的处理器,用于运行Linux+Android系统;BP用于运行实时操作系统(RTOS),通讯协议栈运行于BP的RTOS之上。非通话时间,BP的能耗基本上在5mA左右,而AP只要处于非休眠状态,能耗至少在50mA以上,执行图形运算时会更高。另外LCD工作时功耗在100mA左右,WIFI也在100mA左右。一般手机待机时,AP、LCD、WIFI均进入休眠状态,这时Android中应用程序的代码也会停止执行。

Android为了确保应用程序中关键代码的正确执行,提供了Wake Lock的API,使得应用程序有权限通过代码阻止AP进入休眠状态。但如果不领会Android设计者的意图而滥用Wake Lock API,为了自身程序在后台的正常工作而长时间阻止AP进入休眠状态,就会成为待机电池杀手。

那么Wake Lock API具体有啥用呢?心跳包从请求到应答,断线重连重新登陆等关键逻辑的执行过程,就需要Wake Lock来保护。而一旦一个关键逻辑执行成功,就应该立即释放掉Wake Lock了。两次心跳请求间隔5到10分钟,基本不会怎么耗电。

二、WakeLock使用

获取WakeLock实例代码如下:

PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
WakeLock wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "MyWakelockTag");

newWakeLock(int levelAndFlags, String tag)中PowerManager.PARTIIAL_WAKE_LOCK是一个标志位,标志位是用来控制获取的WakeLock对象的类型,主要控制CPU工作时屏幕是否需要亮着以及键盘灯需要亮着,标志位说明如下:

levelAndFlags CPU是否运行 屏幕是否亮着 键盘灯是否亮着
PARTIAL_WAKE_LOCK
SCREEN_DIM_WAKE_LOCK 低亮度
SCREEN_BRIGHT_WAKE_LOCK 高亮度
FULL_WAKE_LOCK

特殊说明:自API等级17开始,FULL_WAKE_LOCK将被弃用。应用应使用FLAG_KEEP_SCREEN_ON

WakeLock类可以用来控制设备的工作状态。使用该类中的acquire可以使CPU一直处于工作的状态,如果不需要使CPU处于工作状态就调用release来关闭。

(1)、自动release

如果我们调用的是acquire(long timeout)那么就无需我们自己手动调用release()来释放锁,系统会帮助我们在timeout时间后释放。

(2)、手动release

如果我们调用的是acquire()那么就需要我们自己手动调用release()来释放锁。

最后使用WakeLock类记得加上如下权限:

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

注意:在使用该类的时候,必须保证acquirerelease是成对出现的。

三、保持屏幕常亮

最好的方式是在Activity中使用FLAG_KEEP_SCREEN_ON的Flag。

1 public class MainActivity extends Activity {
2     @Override
3     protected void onCreate(Bundle savedInstanceState) {
4         super.onCreate(savedInstanceState);
5         setContentView(R.layout.activity_main);
6         getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
7     }
8 }

这个方法的好处是不像唤醒锁(wake locks),需要一些特定的权限(permission)。并且能正确管理不同app之间的切换,不用担心无用资源的释放问题。

另一个方式是在布局文件中使用android:keepScreenOn属性:

1 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
2
3     android:layout_width="match_parent"
4     android:layout_height="match_parent"
5     android:keepScreenOn="true">
6     ...
7 </RelativeLayout>

android:keepScreenOn = ”true“的作用和FLAG_KEEP_SCREEN_ON一样。使用代码的好处是你允许你在需要的地方关闭屏幕。

注意:一般不需要人为的去掉FLAG_KEEP_SCREEN_ON的flag,windowManager会管理好程序进入后台回到前台的的操作。如果确实需要手动清掉常亮的flag,使用getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)

四、WakefulBroadcastReceiver + IntentService实例

IntentService使用请参照我之前博客:Android IntentService使用介绍以及源码解析

WakefulBroadcastReceiver是BroadcastReceiver的一种特例。它会为你的APP创建和管理一个PARTIAL_WAKE_LOCK类型的WakeLock。WakefulBroadcastReceiver把工作交接给service(通常是IntentService),并保证交接过程中设备不会进入休眠状态。如果不持有WakeLock,设备很容易在任务未执行完前休眠。最终结果是你的应用不知道会在什么时候能把工作完成,相信这不是你想要的。

使用startWakefulService()方法来启动服务,与startService()相比,在启动服务的同时,并启用了唤醒锁。

当后台服务的任务完成,要调用WLWakefulReceiver.completeWakefulIntent()来释放唤醒锁。

WLWakefulReceiver类如下:

 1 public class WLWakefulReceiver extends WakefulBroadcastReceiver {
 2
 3     private static final String TAG = "myTag";
 4
 5     @Override
 6     public void onReceive(Context context, Intent intent) {
 7         //
 8         String extra = intent.getStringExtra("msg");
 9         Log.i(TAG, "onReceive:"+extra);
10         Intent serviceIntent = new Intent(context, MyIntentService.class);
11         serviceIntent.putExtra("msg", extra);
12        startWakefulService(context, serviceIntent);
13     }
14 }

很简单,就是打印一下信息以及调用startWakefulService方法来启动服务。

MyIntentService类如下:

 1 public class MyIntentService extends IntentService {
 2
 3     private static final String TAG = "myTag";
 4
 5     public MyIntentService() {
 6         super("MyIntentService");
 7     }
 8
 9     @Override
10     protected void onHandleIntent(Intent intent) {
11         //子线程中执行
12         Log.i(TAG, "onHandleIntent");
13         for (int i = 0; i < 10; i++) {
14             try {
15                 Thread.sleep(3000);
16                 String extra = intent.getStringExtra("msg");
17                 Log.i(TAG, "onHandleIntent:"+extra);
18             } catch (InterruptedException e) {
19                 e.printStackTrace();
20             }
21         }
22         //调用completeWakefulIntent来释放唤醒锁。
23         WLWakefulReceiver.completeWakefulIntent(intent);
24     }
25 }

同样很简单,也是打印信息进行耗时操作,但是执行完自己业务逻辑后一点记得调用completeWakefulIntent来释放唤醒锁。

最后就是启动广播接收者以及加入权限和声明了:

Intent intent = new Intent("WANG_LEI");
intent.putExtra("msg", "学习WAKE_LOCK。。。");
sendBroadcast(intent);

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

<receiver android:name=".WLWakefulReceiver" >
            <intent-filter>
                <action android:name="WANG_LEI" />
            </intent-filter>
</receiver>
<service android:name=".MyIntentService"></service>

好了,编写好程序运行发现及时按电源键屏幕关闭依然有LOG打印出。

本篇到此结束,wakelock锁主要是相对系统的休眠而言的,意思就是我的程序给CPU加了这个锁那系统就不会休眠了,这样做的目的是为了全力配合我们程序的运行。有的情况如果不这么做就会出现一些问题,比如微信等及时通讯的心跳包会在熄屏不久后停止网络访问等问题。所以微信里面是有大量使用到了wake_lock锁。希望经过上述共同学习你能正确使用WakeLock,不要做电池杀手。

原文地址:https://www.cnblogs.com/leipDao/p/8241468.html

时间: 2024-10-04 01:28:27

安卓电量优化之WakeLock锁机制全面解析的相关文章

安卓电量优化之JobScheduler使用介绍

一.JobScheduler概述 JobScheduler是安卓5.0版本推出的API,允许开发者在符合某些条件时创建执行在后台的任务.在Android开发中,会存在这些场景:你需要在稍后的某个时间点或者当满足某个特定的条件时执行一个任务,例如当设备接通电源适配器或者连接到WIFI,此时就可以使用JobScheduler了,当一系列预置的条件被满足时,JobScheduler API为你的应用执行一个操作.与AlarmManager不同的是这个执行时间是不确定的.除此之外,JobSchedule

SQLServer2012 锁机制测试解析

SQLServer2012在查询分析器里面开两个连接 插入锁: 结论:“表锁”锁定对该表的Select.Update.Delete操作,但不影响对该表的Insert操作也不影响以主键Id为条件的Select,所以Select如果不想等待就要在Select后加With(Nolock),但这样会产生脏数据就是其他事务已更新但并没有提交的数据,如果该事务进行了RollBack则取出的数据就是错误的,所以好自己权衡利弊,一般情况下90%以上的Select都允许脏读,只有账户金额相关的不允许. -----

锁机制及锁优化

   锁      在Java中目前有两种锁机制防止代码块受到并发访问的干扰:.java语言提供了一个synchronized (内部锁)或Lock/Condition(显示锁) 关键达到这一目的,在java SE 5.0引入了Lock/ReentranLock(重入锁)类. 锁具有以下作用: (1)锁用来保护代码片段,任何时刻只能有一个线程执行被保护的代码. (2)锁可以哦管理视图进入被保护代码段的线程 (3)锁可以拥有一个或多个相关条件对象 (4)每个条件对象管理哪些已经进入被保护的代码片段

大数据技术之_29_MySQL 高級面试重点串讲_02_Mysql 简介+Linux 版的安装+逻辑架构介绍+性能优化+性能分析+查询截取分析+分区分库分表简介+锁机制+主从复制

第1章 Mysql 简介1.1 概述1.2 高级 MySQL第2章 Mysql Linux 版的安装2.1 下载地址2.2 检查当前系统是否安装过 mysql2.3 修改 Mysql 配置文件位置2.4 修改字符集和数据存储路径2.5 MySQL 的安装位置说明2.6 Mysql 配置文件说明2.7 Mysql 的数据存放目录第3章 Mysql 逻辑架构介绍3.1 总体概览3.2 查询说明第4章 Mysql 性能优化4.1 影响 mysql 的性能因素4.2 查询与索引优化分析4.2.1 性能下

Android电量优化

最近领导老是反映说我们的APP耗电要比以前厉害一些,排在耗电量的首位,上黑名单了,需要进行电量优化!经过一段时间的研究,自己做了一部分的总结! 电量优化的工具battery-historien battery-historien是google开源的电量检测分析的工具,由于很多APP开发者对电量这快关注不是那么多,star数并不是特别多! 链接:https://github.com/google/battery-historian上面有具体环境搭建步骤! 环境搭建步骤 我使用的是方法二,步骤如下:

Mysql中那些锁机制之InnoDB

我们知道mysql在曾经.存储引擎默认是MyISAM.可是随着对事务和并发的要求越来越高,便引入了InnoDB引擎.它具有支持事务安全等一系列特性. InnoDB锁模式 InnoDB实现了两种类型的行锁. 共享锁(S):同意一个事务去读一行,阻止其它事务获得同样的数据集的排他锁. 排他锁(X):同意获得排他锁的事务更新数据,可是组织其它事务获得同样数据集的共享锁和排他锁. 能够这么理解: 共享锁就是我读的时候,你能够读,可是不能写.排他锁就是我写的时候.你不能读也不能写.事实上就是MyISAM的

并发编程(四):也谈谈数据库的锁机制

http://www.2cto.com/database/201403/286730.html 1. 数据库并发的问题 数据库带来的并发问题包括: 1. 丢失更新. 2. 未确认的相关性(脏读). 3. 不一致的分析(非重复读). 4. 幻像读. 详细描述如下: 1.1.丢失更新 当两个或多个事务选择同一行,然后基于最初选定的值更新该行时,会发生丢失更新问题.每个事务都不知道其它事务的存在.最后的更新将重写由其它事务所做的更新,这将导致数据丢失. e.g.事务A和事务B同时修改某行的值, 事务A

SqlServer锁机制与实践

在如今这个云计算,大数据,移动互联网大行其道的时代,各种NoSQL数据库MongoDb.redis.HBase等使用的越来越广泛,大有替代关系型数据库的趋势.但是关系型数据库真的已经落伍了吗?答案是否定的.非关系型数据库不支持ACID属性,不支持事务,无法适应复杂查询的缺点.关系型数据库凭借其强一致性的特点,注定了在类似银行转账,订单支付等场景中,还是唯一的选择.众所周知,SQLSERVER通过锁来提供ACID属性,处理并发访问,本文尝试通过对锁机制的一些学习,让我们明白数据库查询超时,死锁等问

数据库 锁机制

锁的基本原理 为了保证数据的完事性和一致性,数据库系统采用锁来实现事务的隔离性.各种大型数据库采用的锁基本理论是一致的,但在具体实现上各有差别. 从并发事务锁定的关系上看,可以分为共享锁定和独占锁定.从锁定的对象不同,一般可以分为表锁定和行锁定. 锁 共享锁用于读取数据操作,它是非独占的,允许其他事务同时读取其锁定的资源,但不允许其他事务更新它. 独占锁也叫排他锁,适用于修改数据的场合.它所锁定的资源,其他事务不能读取也不能修改. 当一个事务访问某种数据库资源时,如果执行select语句,必须先