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 使用
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 来关闭。
- 自动 release
如果我们调用的是 acquire(long timeout),那么就无需我们自己手动调用 release() 来释放锁,系统会帮助我们在 timeout 时间后释放。
- 手动 release
如果我们调用的是 acquire() 那么就需要我们自己手动调用 release() 来释放锁。
最后使用 WakeLock 类记得加上如下权限:
注意:在使用该类的时候,必须保证 acquire 和 release 是成对出现的。
屏幕保持常亮
当设备从休眠状态中,被应用程序唤醒一瞬间会耗电过多,我们可以保持屏幕常亮来节省电量,代码声明:
// 屏幕保持常亮
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
// 一般不需要人为的去掉 FLAG_KEEP_SCREEN_ON 的 flag,
// windowManager 会管理好程序进入后台回到前台的的操作
//getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
或者,直接在布局中加上 keepScreenOn = true :
<android.support.constraint.ConstraintLayout xmlns:android=“http://schemas.android.com/apk/res/android”
xmlns:app=“http://schemas.android.com/apk/res-auto”
xmlns:tools=“http://schemas.android.com/tools”
android:layout_width=“match_parent”
android:layout_height=“match_parent”
android:keepScreenOn=“true”
tools:context=“com.jeanboy.app.batterysample.MainActivity”>
</android.support.constraint.ConstraintLayout>
在 API 21,Google 提供了一个新叫做 Job Scheduler API 的组件来处理这样的场景。Job Scheduler API 允许同时执行多个任务,执行某些指定的任务时不需要考虑时机控制引起的电池消耗。
使用 Job Scheduler,应用需要做的事情就是判断哪些任务是不紧急的,可以交给 Job Scheduler 来处理,Job Scheduler 集中处理收到的任务,选择合适的时间,合适的网络,再一起进行执行。
下面是使用 Job Scheduler 的一段简要示例,需要先有一个 JobService:
public class MyJobService extends JobService {
@Override
public boolean onStartJob(JobParameters params) {
Log.i(“MyJobService”, "Totally and completely working on job "
- params.getJobId());
// 检查网络状态
if (isNetworkConnected()) {
new SimpleDownloadTask() .execute(params);
// 返回 true,表示该工作耗时,
// 同时工作处理完成后需要调用 onStopJob 销毁(jobFinished)
return true;
} else {
Log.i(“MyJobService”, "No connection on job " + params.getJobId()
- “; sad face”);
}
// 返回 false,任务运行不需要很长时间,到 return 时已完成任务处理
return false;
}
@Override
public boolean onStopJob(JobParameters params) {
Log.i(“MyJobService”, "Something changed, so I’m calling it on job "
- params.getJobId());
// 有且仅有 onStartJob 返回值为 true 时,才会调用 onStopJob 来销毁 job
// 返回 false 来销毁这个工作
return false;
}
private boolean isNetworkConnected() {
ConnectivityManager connectivityManager =
(ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();
return (networkInfo != null && networkInfo.isConnected());
}
private class SimpleDownloadTask extends AsyncTask<JobParameters,
Void, String> {
protected JobParameters mJobParam;
@Override
protected String doInBackground(JobParameters… params) {
mJobParam = params[0];
try {
InputStream is = null;
int len = 50;
URL url = new URL(“https://www.google.com”);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setReadTimeout(10000); // 10 sec
conn.setConnectTimeout(15000); // 15 sec
conn.setRequestMethod(“GET”);
//Starts the query
conn.connect();
int response = conn.getResponseCode();
Log.d(LOG_TAG, "The response is: " + response);
is = conn.getInputStream();
// Convert the input stream to a string
Reader reader = null;
reader = new InputStreamReader(is, “UTF-8”);
char[] buffer = new char[len];
reader.read(buffer);
return new String(buffer);
} catch (IOException e) {
return “Unable to retrieve web page.”;
}
}
@Override
protected void onPostExecute(String result) {
// 当任务完成时,需要调用 jobFinished() 让系统知道完成了哪项任务
jobFinished(mJobParam, false);
Log.i(“SimpleDownloadTask”, result);
}
}
}
定义了 JobService 的子类后,然后需要在 AndroidManifest.xml 中进行声明:
<service android:name=“pkgName.JobSchedulerService”
android:permission=“android.permission.BIND_JOB_SERVICE” />
最后模拟通过点击 Button 触发 N 个任务,交给 JobService 来处理:
public class FreeTheWakelockActivity extends ActionBarActivity {
public static final String LOG_TAG = “FreeTheWakelockActivity”;
TextView mWakeLockMsg;
ComponentName mServiceComponent;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_wakelock);
mWakeLockMsg = (TextView) findViewById(R.id.wakelock_txt);
mServiceComponent = new ComponentName(this, MyJobService.class);
Intent startServiceIntent = new Intent(this, MyJobService.class);
startService(startServiceIntent);
Button theButtonThatWakelocks =
(Button) findViewById(R.id.wakelock_poll);
theButtonThatWakelocks.setText(R.string.poll_server_button);
theButtonThatWakelocks.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
pollServer();
}
});
}
public void pollServer() {
JobScheduler scheduler =
(JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE);
for (int i = 0; i < 10; i++) {
JobInfo jobInfo = new JobInfo.Builder(i, mServiceComponent)
.setMinimumLatency(5000) // 5 seconds
.setOverrideDeadline(60000) // 60 seconds
.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY) // WiFi or data connections
.build();
mWakeLockMsg.append("Scheduling job " + i + “!\n”);
scheduler.schedule(jobInfo);
}
}
}
官方 demo 地址:https://github.com/googlesamples/android-JobScheduler
Energy Profiler 是 Android Profiler 中的一个组件,可帮助开发者找到应用程序能量消耗的位置。
Energy Profiler 通过监控 CPU、网络和 GPS 传感器的使用情况,并以图形化显示每个组件使用多少能量。Energy Profiler 还会显示可能影响能耗的系统事件(WakeLock、Alarms、Jobs 和 Location),Energy Profiler 不直接测量能耗,相反,它使用一种模型来估算设备上每种资源的能耗。
可以在 View > Tool Windows > Android Profiler 中打开 Energy Profiler 界面。
Energy Profiler
Energy Profiler 的具体使用可查看 Android 开发文档 - 使用 Energy Profiler 检查能源使用情况。
Energy Profiler 支持 Android 8.0 (API 26) 及以上的系统,Android 8.0 (API 26) 以下请使用 Battery Historian。
Battery Historian 是一款由 Google 提供的 Android 系统电量分析工具,能够以网页形式展示手机的电量消耗过程。
GitHub 地址:https://github.com/google/battery-historian
本文以 macOS 环境为例,介绍 Battery Historian 的使用。
Windows 环境请参考:Battery Historian 2.0 for windows 环境搭建。
安装 Docker
手动下载 Docker 安装包,下载链接:https://download.docker.com/mac/stable/Docker.dmg。
安装好之后点击图标运行,在顶部菜单栏可以看到一个鲸鱼图标,说明 Docker 正在运行。
然后在控制台输入:
$ docker --version
看到如下内容,说明 Docker 可以正常使用:
Docker version 19.03.1, build 74b1e89
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级安卓工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年最新Android移动开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Android)
分享读者
作者2013年java转到Android开发,在小厂待过,也去过华为,OPPO等大厂待过,18年四月份进了阿里一直到现在。
被人面试过,也面试过很多人。深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长,不成体系的学习效果低效漫长,而且极易碰到天花板技术停滞不前!
我们整理了一份阿里P7级别的Android架构师全套学习资料,特别适合有3-5年以上经验的小伙伴深入学习提升。
主要包括腾讯,以及字节跳动,阿里,华为,小米,等一线互联网公司主流架构技术。如果你有需要,尽管拿走好了。
如果你觉得自己学习效率低,缺乏正确的指导,可以点击加入资源丰富,学习氛围浓厚的技术圈一起学习交流吧!
群内有许多来自一线的技术大牛,也有在小厂或外包公司奋斗的码农,我们致力打造一个平等,高质量的Android交流圈子,不一定能短期就让每个人的技术突飞猛进,但从长远来说,眼光,格局,长远发展的方向才是最重要的。
35岁中年危机大多是因为被短期的利益牵着走,过早压榨掉了价值,如果能一开始就树立一个正确的长远的职业规划。35岁后的你只会比周围的人更值钱。
年java转到Android开发,在小厂待过,也去过华为,OPPO等大厂待过,18年四月份进了阿里一直到现在。
被人面试过,也面试过很多人。深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长,不成体系的学习效果低效漫长,而且极易碰到天花板技术停滞不前!
我们整理了一份阿里P7级别的Android架构师全套学习资料,特别适合有3-5年以上经验的小伙伴深入学习提升。
主要包括腾讯,以及字节跳动,阿里,华为,小米,等一线互联网公司主流架构技术。如果你有需要,尽管拿走好了。
[外链图片转存中…(img-mH0Xpudl-1710898671235)]
如果你觉得自己学习效率低,缺乏正确的指导,可以点击加入资源丰富,学习氛围浓厚的技术圈一起学习交流吧!
群内有许多来自一线的技术大牛,也有在小厂或外包公司奋斗的码农,我们致力打造一个平等,高质量的Android交流圈子,不一定能短期就让每个人的技术突飞猛进,但从长远来说,眼光,格局,长远发展的方向才是最重要的。
35岁中年危机大多是因为被短期的利益牵着走,过早压榨掉了价值,如果能一开始就树立一个正确的长远的职业规划。35岁后的你只会比周围的人更值钱。