Andorid performance optimization (7) summary of power saving development skills

1 Introduction

With today's booming mobile internet, no matter how good a smartphone is, it can escape the situation of charging every day. Whether an app is easy to use or not, the power consumption is also one of the important indicators to measure. Today we will come together to explore the knowledge of power consumption in Android and talk about some development techniques for App to optimize power saving.

2 Get phone battery information

In the development process, if you want to get the battery power information, you can provide a system broadcast through Android: ACTION_BATTERY_CHANGED can get relevant battery information when the battery information changes. Such as the code:

private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
            int health = intent.getIntExtra("health", 0);
            int iconSmall = intent.getIntExtra("Icon-small", 0);
            int level = intent.getIntExtra("level", 0);

            boolean present = intent.getBooleanExtra("present", false);
            int plugged = intent.getIntExtra("plugged", 0);
            int scale = intent.getIntExtra("scale", 0);
            int status = intent.getIntExtra("status", 0);
            String technology = intent.getStringExtra("technology");
            int temperature = intent.getIntExtra("temperature", 0);
            int voltage = intent.getIntExtra("voltage", 0);
        }
    }
};

The corresponding variables of battery information are described as follows:

variable

Types of

Explanation

health

int

Get the health status of the battery. The returned status type is determined by the constants defined by the android.os.BatteryManager class, including:

The battery is damaged (BATTERY_HEALTH_DEAD)

Battery health (BATTERY_HEALTH_GOOD)

The battery is too hot (BATTERY_HEALTH_OVERHEAT)

The battery voltage is too high (BATTERY_HEALTH_OVER_VOLTAGE)

Unknown status (BATTERY_HEALTH_UNKOWN)

Unspecified failure (BATTERY_HEALTH_UNSPECIFIED_FAILURE)

iconSmall

int

Get the icon ID corresponding to the battery

level

int

Get the remaining capacity of the battery

present

boolean

Determine whether there is currently a battery

plugged

int

The type of power outlet connected. The returned status is determined by the constants defined by the android.os.BatteryManager class, including:

USB 电源( BATTERY_PLUGGED_USB )

AC power supply (BATTERY_PLUGGED_AC)

scale

int

Get the total capacity of the battery, usually 100

status

int

Get the battery status. The returned status type is determined by the constants defined by the android.os.BatteryManager class, including:

Battery charge status (BATTERY_STATUS_CHARGING)

Battery discharge status (BATTERY_STATUS_DISCHARGING)

Full battery status (BATTERY_STATUS_FULL)

The battery is not charged (BATTERY_STATUS_NOT_CHARGING)

Unknown battery status (BATTERY_STATUS_UNKNOWN)

technology

String

Get the type of battery

temperature

int

Get the battery temperature in Celsius

voltage

int

Get the battery voltage

3 Analysis of electricity

After Android5.0, Google open sourced a tool for detecting battery related information and events-Battery Historian. The tool is very powerful for parsing bugreport.txt into Html representation, and then visually display and analyze the power consumption of related indicators, and can also screen the App to give a summary description to help us identify power consumption behaviors.

3.1 Generate bugreport.txt file

bugreport.txt is to export the battery power information file of the mobile phone through the adb command, the steps can be as follows:

Step 1: Clear the existing power consumption data, execute the command: adb shell dumpsys batterystats --enable full-wake-history

Step 2 : Reset the device power consumption data, execute the command: adb shell dumpsys batterystats --reset

Step 3: Launch the App on the phone to perform related operations

Step 4. Execute the command before Android 7.0: adb bugreport> bugreport.txt, and execute the command for Android 7.0 and later: adb bugreport bugreport.zip. You can export the bugreport file to your computer, and also generate a txt or zip file in the phone directory /data/user_de/0/com.android.shell/files/bugreports.

3.2 Install Battery Historian

Battery Historian Github官方介绍了两种使用方式,分别是使用使用Docker和编译源码。如果你使用的是MAC系统,建议使用第一种方式,就是通过Docker来安装Battery Historian,在安装完Docker后在终端运行命令:docker run -d -p 9999:9999 bhaavan/battery-historian,然后等待下载完成即可。如:

如果你使用的是Win7系统,那么就只能使用第二种安装方法,步骤如下。

步骤一:下载和安装GO编程语言,并配置环境变量,正常情况下安装成功会自动生成环境变量,如果没有则要自己动手设置一下。

a.配置环境变量GOROOT、GOPATH以及Path:

b.检查是否安装成功:

 

步骤二:下载和安装Git,并配置环境变量。

步骤三:下载和安装Python2.7(注意:是Python2.7,不是Python3),并配置环境变量。

步骤四:下载和安装Java,并配置环境变量。

步骤五:打开C:\Program Files\Git\git-bash.exe,并执行命令:go get -d -u github.com/google/battery-historian/...

使在 %USERPROFILE%\go\src\github.com\google目录下载battery-historian工程源码:

步骤六:同样,通过命令:go get -u github.com/golang/protobuf/protoc-gen-go

使在 %USERPROFILE%\go\src\github.com\golang\目录下载protobuf工程源码:

步骤七:执行命令:cd $GOPATH/src/github.com/google/battery-historian

进入到battery-historian目录下,并执行命令:go run setup.go

该命令主要是在%USERPROFILE%\go\src\github.com\google\battery-historian\third_party目录下创建third_party文件夹,并下载 closure-compilerclosure-libraryflot-axislabels。如果因为超时不成功,可以自行进行下载后放入目录即可:

步骤八:执行命令:cd $GOPATH/src/github.com/google/battery-historian

进入到battery-historian目录下,并执行命令:go run cmd/battery-historian/battery-historian.go

至此,Battery Historian便完装完成。

3.3 分析bugreport

Battery Historian完装完成后,便可在浏览器中进行访问http://localhost:9999 (9999是默认的端口,在安装中可以指定),如下图:

上传bugreport.txt或bugreport.zip文件后便可以进行分析了,笔者在写文章时尝试进行上传bugreprot,但因为国内对谷歌访问的限制,始终不能显示提交按钮,所以并没有成功,所以只能贴一张官网上样图:

4 电量优化技巧

Android开发中,反映一个App电量的消耗主要由:CPU、位置服务、wakelock、传感器、数据传输等组件的使用情况决定。

4.1 位置服务的使用

先择合适的定位服务

Android系统为开发者提供了三种定位服务:

GPS_PROVIDER

GPS定位,利用GPS芯片通过接收全球定位系统的卫星提供的经纬度坐标信息实现位置服务,需要ACCESS_FINE_LOCATION权限。这种方式定位耗电也是最高,精准度也是最高,通常在10米以内。

NETWORK_PROVIDER

网络定位,通过移动通信的基站信号和Wifi节点的地址来大致计算出手机所在的位置,需要ACCESS_COARSE_LOCATION或者ACCESS_FINE_LOCATION权限。这种方式定位精度比GPS定位差很多,通常在几百米范围内。

PASSIVE_PROVIDER

被动定位,使用其他应用或者系统组件发起定位请求后保存下来的位置信息。这种方式是最省电的。

我们在实际开发中需要综合考虑App的具体需要在不同时机采用不同的定位服务。一般地往往在实际开发中很多App通常会选择第三方的定位SDK,像百度定信、高德定位,因为这些SDK无论在定位时间还是定位精度还是耗电量方面都做出专门的优化,还是非常靠谱的。

合理注册和注销定位监听

一般地我们会在Activoity的onResume和onPause两个生命周期回调中做注册和注销定位服务的监听。如代码:

public void onResume(){
    super.onResume();
    locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 6000, 100, locationListener);
}

public void onPause() {
    super.onPause();
    locationManager.removeUpdates(locationListener);
}

Android SDK提供了requestLocationUpdates方法进行位置更新监听的注册,请注意方法的第二和第三个参数,分别是指位置更新通知的最小时间间隔毫秒数和最小单位为米的距离。我们需要根据具体的业务需求设置一个合适的更新频率值,通常需要在定位精度和耗电量之间综合考虑。

在获取到定位之后或者程序处于后台时,需要及时注销位置监听,因为长时间的监听位置更新会耗费大量的电量。

4.2 慎用WakeLock

Android系统中为了节省电量,在设置里设定了会在用户无操作一段时间之后进入休眠状态。但有时候,我们需要使手机一直处于一种唤醒的状态,例如一些播放器的App,在播放视频时就算不操作屏幕也不需要进入休眠状态,从而保证良好的用户体验。这时就需要使用WakeLock。WakeLock它是一种锁机制,只要拿着该锁,系统就无法进入休眠,同时也可使App更加的耗电。

WakeLock的锁类型有很多种,不同的类型对cpu、屏幕和键盘的影响不相,具体情况如下:

PARTIAL_WAKE_LOCK                     保持CPU正常运转,但屏幕和键盘灯可能是关闭的。

SCREEN_DIM_WAKE_LOCK             保持CPU正常运转,允许屏幕点亮但可能是置灰的,键盘灯可能是关闭的。

SCREEN_BRIGHT_WAKE_LOCK        保持CPU正常运转,允许屏幕高亮度显示,键盘灯可能是关闭的。

FULL_WAKE_LOCK                          保持CPU正常运转,允许屏幕高亮度显示,键盘灯也保持亮度。

ACQUIRE_CAUSES_WAKEUP           强制屏幕和键盘灯亮起,这种锁针对一些必须通知用户的操作。

ON_AFTER_RELEASE                       当WakeLock被释放后,继续保持屏幕和键盘灯开启一定时间。

WakeLock的使用如下:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    PowerManager pm = (PowerManager)getSystemService(Context.POWER_SERVICE);
    mWakeLock = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK, this.getClass().getName());
}

@Override
protected void onResume() {
    super.onResume();
    mWakeLock.acquire(60 * 1000);
}

@Override
protected void onPause() {
    super.onPause();
    mWakeLock.release();
}

在使用WakeLock时,建议在申请时传入超时参数,防止由于忘记或者异常情况下没有释放锁,还要切记在任务结束之后及时释放锁,如果不是会导至屏幕一直显示很长一段时间从而耗费了手机的电量。

4.3 传感器合理使用

Android提供了对设备传感器的支持,只要设备的硬件有支持这些传感器,App就可以通过传感器来获取设备的外界条件,包括手机的运行状态、当前摆放的方向等。

传感器几个常用的类型有:

Sensor.TYPE_ORIENTATION              方向传感器

Sensor.TYPE_ACCELEROMETER        重力传感器

Sensor.TYPE_LIGHT                          光线传感器

Sensor.TYPE_MAGNETIC_FIELD         磁场传感器

传感器频率总共分为4等,分别是:

SensorManager.SENSOR_DELAY_FASTEST       最快,延迟最小。

SensorManager.SENSOR_DELAY_GAME          适合游戏的频率。

SensorManager.SENSOR_DELAY_NORMAL     正常频率。

SensorManager.SENSOR_DELAY_UI                适合普通用户界面UI变化的频率。

Android为我们提供了这几个采样率的参数,方便我们使用。但对于选择那种采样率而言,并不是越快越好,要参照实际开发的应用的情况来说,越高的采样率类型就会越费耗电量。

传感器的使用如下:

private SensorManager mSensorManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    mSensorManager = (SensorManager)getSystemService(Context.SENSOR_SERVICE);
}
@Override
protected void onResume() {
    super.onResume();
    mSensorManager.registerListener(mSensorEventListener, mSensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION), SensorManager.SENSOR_DELAY_GAME);
}
@Override
protected void onPause() {
    super.onPause();
    mSensorManager.unregisterListener(mSensorEventListener);
}

在使用传感器时,一定要切记在任务结束之后或者处理后台时要及时注销传感器的监听。

4.4 数据传输技巧

Android中的数据传输方式有很多种,如常见的:蓝牙、Wifi、蜂窝数据。无论哪一种传输方式,为了更好地延长电池的使用时间,我们在使用过程中都需要重点关注几点:

1 处于后台时根据具体业务需求,严格限制App处于后台时是否需要继续真的需要数据传输,尽量能够避免无效的数据传输。

2 数据传输的频率问题,要确定好数据传输的频率,避免冗余重复的数据传输,同时一定要避免轮询情况。

3 数据传输中要进行压缩数据大小,合并网络请求。

4 失效重试机制,要注意重试是在网络正常的情况下才去重试,否则除了没有重试成功外,而且还增加了消耗电量。

更多的网络数据传输技巧,请见《Andorid性能优化(八) 之 网络请求优化》

4.5 反注册后台BroadcastReceiver

减少应用损耗的电量,那么就要尽量避免无用的操作代码的执行。例如广播的使用中,如果App退到后台,一切界面刷新都是没有意义的而且会浪费内存和电量,所以通常的做法是在Activity的onPause方法回调时根据具体业务需要选择是否应该反注册广播。

4.6 AlarmManager使用上注意

AlarmManager是一个系统级别的服务,它可以在特定的时刻广播一个指定的Intent。AlarmManager常用的方法有:

set                       设置一次性的闹钟操作。

setRepeating        设置重复性的闹钟操作。事实上,seatRepeating方法并不靠谱。根据资料:在API 19(即Kitkat)之后,这一方法将不再准确地保证每次工作都在你设置的时间开始。原来,操作系统为了节能省电,将会调整alarm唤醒的时间。故通过AlarmManager.setRepeating()方法将不再保证你定义的工作能按时开始。

AlarmManager的唤醒操作也是比较耗电的,通常情况下需要保证两次唤醒操作的时间间隔不要太短,在不需要使用唤醒功能的情况下应尽早取消它,否则会一直处于耗电状态。

4.7善用JobScheduler

Android5.0后提供了作业调度器JobScheduler。它的作用是让系统在某个时刻某个特定条件下批处理一些APP的任务请求,而且这项任务的执行是在你自己的应用程序进程中。它的具体使用可见前面文章《Android里JobScheduler的实现》 。它可以对任务进行排期,例如设备在充电或者空闲的时候才执行一些特定任务从而达到优化耗电的任务安排方式的效果。

 

 

 

 

 

 

 

发布了106 篇原创文章 · 获赞 37 · 访问量 8万+

Guess you like

Origin blog.csdn.net/lyz_zyx/article/details/85842950