• Android App耗电量统计

    2017-01-19 15:16:32
    还没有完成的,初稿App耗电量统计:源码 PowerUsageSummary.java 继承PowerUsageBase.java类 BatteryHistoryPreference类--sp 获取耗电量历史(读取sp文件)--sp文件数据来自xml文件(power_usage_summary.xml) ...
    还没有完成的,初稿

    App耗电量统计:源码

    • PowerUsageSummary.java 继承PowerUsageBase.java类
    BatteryHistoryPreference类--sp 获取耗电量历史(读取sp文件)--sp文件数据来自xml文件(power_usage_summary.xml)
    PreferenceGroup类--统计所有App耗电量同history
    
    refreshStats()方法刷新耗电量状态:内部有以下几个类(BatteryStatsHelper.java)获取
    1.PowerProfile:提供部件电流数值。
    2.BatteryStats:App各部件运行时间。(获取封装在BatteryStatsHelper类中具体看下面)
    final BatteryStats stats = mStatsHelper.getStats();
    3.根据BatteryStatsHelper类中统计
    - App耗电量统计:processAppUsage()  
    - 硬件耗电量统计:processMiscUsage()
    获取耗电量更新SP数据: mAppListGroup.addPreference(pref);
    • PowerProfile.java
      (1)Android部件电流信息存于:power_profile.xml

    (2)每个OEM厂商有私有power_profile.xml

    (3)PowerProfile读取power_profile.xml,并提供API访问部件电流数值。

    /**
     * Reports power consumption values for various device activities. Reads values from an XML file.
     * Customize the XML file for different devices.
     * [hidden]
     */
    38public class PowerProfile {
    
     private void readPowerValuesFromXml(Context context) {
        int id = com.android.internal.R.xml.power_profile;//xml文件power_profile.xml
        //下面就是xml解析了根据下面定义节点获取值:
        //private static final String TAG_DEVICE = "device";
        //private static final String TAG_ITEM = "item";
        //private static final String TAG_ARRAY = "array";
        //private static final String TAG_ARRAYITEM = "value";
        //private static final String ATTR_NAME = "name";
        ....
    最后添加数据到sPowerMap (一个HashMap) sPowerMap.put(key, (double) value); key是各部件名称。value是各部件的电流值
    }
    }

    //power_profile.xml 各部件定义的电流值 屏幕 cpu 蓝牙 wifi gps等等

    <device name="Android">  
      <!-- Most values are the incremental current used by a feature,  
           in mA (measured at nominal voltage).  
           The default values are deliberately incorrect dummy values.  
           OEM's must measure and provide actual values before  
           shipping a device.  
           Example real-world values are given in comments, but they  
           are totally dependent on the platform and can vary  
           significantly, so should be measured on the shipping platform  
           with a power meter. -->  
      <item name="none">0</item>  
      <item name="screen.on">100</item>  <!-- ~200mA -->  
      <item name="screen.full">200</item>  <!-- ~300mA -->  
      <item name="bluetooth.active">90.5</item> <!-- Bluetooth data transfer, ~10mA -->  
      <item name="bluetooth.on">2.5</item>  <!-- Bluetooth on & connectable, but not connected, ~0.1mA -->  
      <item name="wifi.on">1.25</item>  <!-- ~3mA -->  
      <item name="wifi.active">130</item>  <!-- WIFI data transfer, ~200mA -->  
      <item name="wifi.scan">100</item>  <!-- WIFI network scanning, ~100mA -->  
      <item name="dsp.audio">30.5</item> <!-- ~10mA -->  
      <item name="dsp.video">72.5</item> <!-- ~50mA -->  
      <item name="radio.active">135</item> <!-- ~200mA -->  
      <item name="radio.scanning">5.3</item> <!-- cellular radio scanning for signal, ~10mA -->  
      <item name="gps.on">30</item> <!-- ~50mA -->  
      <!-- Current consumed by the radio at different signal strengths, when paging -->  
      <array name="radio.on"> <!-- Strength 0 to BINS-1 -->  
          <value>3.5</value> <!-- ~2mA -->  
          <value>2.4</value> <!-- ~1mA -->  
      </array>  
      <!-- Different CPU speeds as reported in  
           /sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state -->  
      <array name="cpu.speeds">  
          <value>624000</value> <!-- 624 MHz CPU speed -->  
          <value>699563</value> <!-- 699 MHz CPU speed -->  
          <value>799500</value> <!-- 799 MHz CPU speed -->  
          <value>899438</value> <!-- 899 MHz CPU speed -->  
          <value>999375</value> <!-- 999 MHz CPU speed -->  
          <value>1099313</value> <!-- 1099 MHz CPU speed -->  
          <value>1199250</value> <!-- 1199 MHz CPU speed -->  
          <value>1299188</value> <!-- 1299 MHz CPU speed -->  
          <value>1399125</value> <!-- 1399 MHz CPU speed -->  
          <value>1499063</value> <!-- 1499 MHz CPU speed -->  
          <value>1599000</value> <!-- 1599 MHz CPU speed -->  
      </array>  
      <!-- Current when CPU is idle -->  
      <item name="cpu.idle">2.2</item>  
      <!-- Current at each CPU speed, as per 'cpu.speeds' -->  
      <array name="cpu.active">//各个cpu频段的功耗  
          <value>54</value>  
          <value>63</value>  
          <value>72</value>  
          <value>80</value>  
          <value>90</value>  
          <value>100</value>  
          <value>109</value>  
          <value>115</value>  
          <value>121</value>  
          <value>127</value>  
          <value>135</value>  
      </array>  
      <!-- This is the battery capacity in mAh (measured at nominal voltage) -->  
      <item name="battery.capacity">2000</item>  
    </device>  
    • BatteryStats.java 抽象类implements Parcelable(android 序列化)
    /**
     * 统计电池各部件使用情况,时间以微秒为单位
     * A class providing access to battery usage statistics, including information on
     * wakelocks, processes, packages, and services.  All times are represented in microseconds
     * except where indicated otherwise. 
     * @hide
     */
    public abstract class BatteryStats implements Parcelable {
        private static final String TAG = "BatteryStats";
    
        private static final boolean LOCAL_LOGV = false;
    
       /** @hide */
        public static final String SERVICE_NAME = "batterystats";
        ....
    }
    • BatteryStatsHelper.java Android BatteryStatsHelper深入理解(and5.1)
      作用:主要是统计各个应用,多用户的每个用户,以及蓝牙,屏幕等耗电统计
      BatteryStatsHelper 的实例在PowerUsageBase类初始化:
    @Override
        public void onAttach(Activity activity) {
           super.onAttach(activity);
           mUm = (UserManager) activity.getSystemService(Context.USER_SERVICE);
           mStatsHelper = new BatteryStatsHelper(activity, true);//实例化
       }

    BatteryStatsHelper.java 类内部方法

    public void create(BatteryStats stats) {  
        mPowerProfile = new PowerProfile(mContext);  
        mStats = stats;  
    }  
    
    public void create(Bundle icicle) {  
        if (icicle != null) {  
            mStats = sStatsXfer;  
            mBatteryBroadcast = sBatteryBroadcastXfer;  
        }  
        mBatteryInfo = IBatteryStats.Stub.asInterface(  
                ServiceManager.getService(BatteryStats.SERVICE_NAME)); //aidl服务 SERVICE_NAME = "batterystats";;
        mPowerProfile = new PowerProfile(mContext);  //从power_profile.xml读取的各个器件的电源消耗参数具体查看上面详解这个类的链接
    } 

    在PowerUsageSummary类分析获取App各部件运行时间 调用BatteryStats stats = mStatsHelper.getStats();

    public BatteryStats getStats() {
           if (mStats == null) {
                load(); //如果mStats为空 调用load方法否则返回mStats
            }
            return mStats;
        }
    
    private void load() {
            if (mBatteryInfo == null) {//mBatteryInfo空判断在Create里面初始化了
                return;
            }
            mStats = getStats(mBatteryInfo); //调用getStats,返回BatteryStatsImpl实现类
            if (mCollectBatteryBroadcast) {
                mBatteryBroadcast = mContext.registerReceiver(null,
                        new IntentFilter(Intent.ACTION_BATTERY_CHANGED));//注册监听电量改变广播
            }
        }
    
    private static BatteryStatsImpl getStats(IBatteryStats service) {
            try {
                ParcelFileDescriptor pfd = service.getStatisticsStream();//BatteryStatsService服务类:收集所有消耗电池信息 调用updateExternalStatsSync()从外部获取数据来源(无线控制器,bluetooth芯片组)和更新batterystats信息。
                if (pfd != null) {
                    try (FileInputStream fis = new ParcelFileDescriptor.AutoCloseInputStream(pfd)) {//下面读取序列化反序列化获取batterystats数据
                        byte[] data = readFully(fis, MemoryFile.getSize(pfd.getFileDescriptor()));
                        Parcel parcel = Parcel.obtain();
                        parcel.unmarshall(data, 0, data.length);
                        parcel.setDataPosition(0);
                        BatteryStatsImpl stats = com.android.internal.os.BatteryStatsImpl.CREATOR
                                .createFromParcel(parcel);
                        return stats;
                    } catch (IOException e) {
                       Log.w(TAG, "Unable to read statistics stream", e);
                    }
                }
            } catch (RemoteException e) {
                Log.w(TAG, "RemoteException:", e);
            }
            return new BatteryStatsImpl();
        }

    接下来就是refreshState更新电池最新状态的,statsType是指充电状态还是非充电状态,asUsers指的是userId(多用户)

    public void refreshStats(int statsType, List<UserHandle> asUsers) {  
        final int n = asUsers.size();  
        SparseArray<UserHandle> users = new SparseArray<UserHandle>(n);  
        for (int i = 0; i < n; ++i) {  
            UserHandle userHandle = asUsers.get(i);  
            users.put(userHandle.getIdentifier(), userHandle);  
        }  
        refreshStats(statsType, users);  
    }  
    
    /** 
     * Refreshes the power usage list. 
     */  
    public void refreshStats(int statsType, SparseArray<UserHandle> asUsers) {  
        refreshStats(statsType, asUsers, SystemClock.elapsedRealtime() * 1000,  
                SystemClock.uptimeMillis() * 1000);  
    } 

    refreshStats方法:processAppUsage()计算每个uid的耗电情况, processMiscUsage();//计算比如屏幕、wifi、蓝牙等耗电

     public void refreshStats(int statsType, SparseArray<UserHandle> asUsers, long rawRealtimeUs,
               long rawUptimeUs) {
            ...
            ...
            ...
            processAppUsage(asUsers);//计算每个uid的耗电情况包含:CPU Wakelock WIFI 蓝牙 传感器 Camera FlashLight MobileRadio
            ...
            ...
            processMiscUsage();//计算比如屏幕、wifi、蓝牙等耗电
            ...
            ...
            }
    
    processAppUsage(asUsers){
     mCpuPowerCalculator.calculateApp(app, u, mRawRealtimeUs, mRawUptimeUs, mStatsType);//每个App Cpu耗电量计算
     mWakelockPowerCalculator.calculateApp(app, u, mRawRealtimeUs, mRawUptimeUs, mStatsType);//每个App Wakelock耗电量计算
     mMobileRadioPowerCalculator.calculateApp(app, u, mRawRealtimeUs, mRawUptimeUs, mStatsType);//每个App MobileRadio耗电量计算
     mWifiPowerCalculator.calculateApp(app, u, mRawRealtimeUs, mRawUptimeUs, mStatsType);//每个App WIFI耗电量计算
     mBluetoothPowerCalculator.calculateApp(app, u, mRawRealtimeUs, mRawUptimeUs, mStatsType);//每个App 蓝牙耗电量计算
     mSensorPowerCalculator.calculateApp(app, u, mRawRealtimeUs, mRawUptimeUs, mStatsType);//每个App 传感器耗电量计算
     mCameraPowerCalculator.calculateApp(app, u, mRawRealtimeUs, mRawUptimeUs, mStatsType);//每个App Camera耗电量计算
     mFlashlightPowerCalculator.calculateApp(app, u, mRawRealtimeUs, mRawUptimeUs, mStatsType);//每个App Flashlight耗电量计算
     }
    
     private void processMiscUsage() {
       addUserUsage();
       addPhoneUsage();
       addScreenUsage();
       addWiFiUsage();
       addBluetoothUsage();
       addIdleUsage(); // Not including cellular idle power
       // Don't compute radio usage if it's a wifi-only device
       if (!mWifiOnly) {
          addRadioUsage();
         }
       }
    • BatteryEntry.java

    看源码解释:相当于bean耗电量数据(package name , icon , iconId; // For passing to the detail screen.)
    内部维护一个 NameAndIconLoader线程去加载BatteryEntry数据。

    /**
    41 * Wraps the power usage data of a BatterySipper with information about package name
    42 * and icon image.
    43 */

    构造函数统计硬件软件App信息:

     public BatteryEntry(Context context, Handler handler, UserManager um, BatterySipper sipper) {
    130        sHandler = handler;
    131        this.context = context;
    132        this.sipper = sipper;
    133        switch (sipper.drainType) {
    134            case IDLE:
    135                name = context.getResources().getString(R.string.power_idle);
    136                iconId = R.drawable.ic_settings_phone_idle;
    137                break;
    138            case CELL:
    139                name = context.getResources().getString(R.string.power_cell);
    140                iconId = R.drawable.ic_settings_cell_standby;
    141                break;
    142            case PHONE://通话
    143                name = context.getResources().getString(R.string.power_phone);
    144                iconId = R.drawable.ic_settings_voice_calls;
    145                break;
    146            case WIFI://wifi
    147                name = context.getResources().getString(R.string.power_wifi);
    148                iconId = R.drawable.ic_settings_wireless;
    149                break;
    150            case BLUETOOTH://蓝牙
    151                name = context.getResources().getString(R.string.power_bluetooth);
    152                iconId = R.drawable.ic_settings_bluetooth;
    153                break;
    154            case SCREEN://屏幕
    155                name = context.getResources().getString(R.string.power_screen);
    156                iconId = R.drawable.ic_settings_display;
    157                break;
    158            case FLASHLIGHT:
    159                name = context.getResources().getString(R.string.power_flashlight);
    160                iconId = R.drawable.ic_settings_display;
    161                break;
    162            case APP:
    163                name = sipper.packageWithHighestDrain;
    164                break;
    165            case USER: {
    166                UserInfo info = um.getUserInfo(sipper.userId);
    167                if (info != null) {
    168                    icon = Utils.getUserIcon(context, um, info);
    169                    name = Utils.getUserLabel(context, info);
    170                } else {
    171                    icon = null;
    172                    name = context.getResources().getString(
    173                            R.string.running_process_item_removed_user_label);
    174                }
    175            } break;
    176            case UNACCOUNTED:
    177                name = context.getResources().getString(R.string.power_unaccounted);
    178                iconId = R.drawable.ic_power_system;
    179                break;
    180            case OVERCOUNTED:
    181                name = context.getResources().getString(R.string.power_overcounted);
    182                iconId = R.drawable.ic_power_system;
    183                break;
    184            case CAMERA:
    185                name = context.getResources().getString(R.string.power_camera);
    186                iconId = R.drawable.ic_settings_camera;
    187                break;
    188        }
    189        if (iconId > 0) {
    190            icon = context.getDrawable(iconId);
    191        }
    192        if ((name == null || iconId == 0) && this.sipper.uidObj != null) {
    193            getQuickNameIconForUid(this.sipper.uidObj.getUid());
    194        }
    195    }

    总结:

    1.Android电量消耗统计在:BatteryStatsHelper类
    2.getPowerProfile() 获取PowerProfile,PowerProfile类是(读取power_profile.xml文件)获取Android各部件电流值
    3.getStats()获取BatteryStats(App各部件运行时间微秒为单位),通过BatteryStatsService服务类:收集所有消耗电池信息 调用updateExternalStatsSync()从外部获取数据来源(无线控制器,bluetooth芯片组)和更新batterystats信息。
    4.refreshState更新电池最新状态
    - processAppUsage() :App耗电量统计
    - processMiscUsage() :硬件耗电量统计

    参考:http://www.cnblogs.com/hyddd/p/4402621.html

    展开全文
  • 这个应用很简单就是获取Android中手机中应用用电排行的,很方便实用的
  • Android App 电量分析  耗电操作主要分为下面几种 高频通信 CPU密集型的计算 传感器  频繁唤醒系统 解决方案 -减少:您的应用可以裁剪多少操作?例如,它可以缓存下载的数据,而不是重复唤醒无线电重新下载...

    分为新老两个版本的SDK-TOOL,新版的放在另外一篇博客

    Android App 电量分析

     耗电操作主要分为下面几种

    1. 高频通信
    2. CPU密集型的计算
    3. 传感器
    4.  频繁唤醒系统

    解决方案

    • -减少:您的应用可以裁剪多少操作?例如,它可以缓存下载的数据,而不是重复唤醒无线电重新下载数据?
    • -推迟:应用程序是否需要立即执行操作?例如,它是否可以等到设备充电才将数据备份到云端?
    •  合并:可以批量工作,而不是多次将设备置于活动状态?例如,真的有必要让几十个应用程序分别在不同的时间打开收音机发送消息?在一次唤醒收音机的过程中,信息可以传输吗?

    举例:

     

    • - 高频通信,使用合并或者裁剪的方式解决
      •     -所有的推送都用统一的推送服务,比如谷歌推送或者小米推送
      •     - 同时连接多个智能设备进行通信,真的有这个必要么,不需要的尽早断开长链接吧
    • - CPU密集型,把一定的计算量放到服务器去执行
    • - 传感器,类似于GPS之类的,看场景把这个没有太好的办法

    测试工具

    这里推荐两个:一个是Google官方提供的Battery Historian,一个是腾讯提供的一个测试电量的工具GT


    使用Battery Historian分析电量使用情况

    Battery Historian工具提供了一段时间内设备电池消耗的深入分析。在全系统级别,该工具以HTML表示形式从系统日志中查看与电源相关的事件。在特定应用程序级别,该工具提供了各种数据,可帮助您确定电池耗尽应用程序的行为。

    ![image]

     

    - 大约在早上6:50,可视化显示电池电量相对急剧下降。

     图表分析
     系统整体分析

     

    • - 排序方式(选择:电量使用估计 device estimated power use)
      • 选择右方的systemstats(系统统计),查看是什么原因导致的耗电量过高
      • 第二行能看到按耗电量排序的App,确定了耗电高的应用,再去看看耗电高的原因

    单个应用分析

     

    • 在App Selection下选择按名字筛选,选择应用的包名称
    • 在Tables下选择,device estimated power use
    • 选择右方的systemstats(系统统计),查看自己应用在哪些方面耗电量过高

    根据特定的应用程序,以下数据可视化类别将更改为显示特定于应用程序的数据
        - SyncManager.
        - Foreground process.
        - Userspace Wakelock.
        - Top app.
        - JobScheduler.
        - Activity Manager Proc.
    电池电量急剧下降,显示了三件事情:
    - CPU正在运行,
    - 应用程序已获取唤醒锁,
    - 并且屏幕已打开。
     

    SDK-TOOL版本小于25的使用下面指令

    因为SDK下面的platform-tool的更新,所以不同版本的方式不一定管用

    SDK-TOOl 版本小于25的应该是用这些指令

    adb shell dumpsys batterystats --enable full-wake-history
    //首先要初始化batterystats数据
    adb shell dumpsys batterystats --reset
    //使用monkey对要进行电量测试的应用进行操作
    adb shell monkey -p 包名 -v 1000
    // 收集Battery数据: 
    adb shell dumpsys batterystats > batterystats.txt 
    // battery-historian来生成我们可见HTML报告
    python historian.py batterystats.txt > batterystats.html



    SDK-TOOL版本大于于25的使用下面指令


    然后再用GoLang去分析,由于环境比较复杂,新开一篇文章详情见Android App 电量分析

    要从运行Android 7.0及更高版本的开发设备获取错误报告:
    
    $ adb bugreport bugreport.zip
    对于6.0及更低版本的设备:
    // 在高版本的SDK中,这条命令会提示不能打包压缩,而日志内容有几十M,一般需要等待一两分钟
    $ adb bugreport > bugreport.txt

     

    展开全文
  • 可能很多公司连QA/Tester也不会关注测试App电量的使用. 一般来说开发和测试的测试设备也一直是连着USB处于充电状态的, 感官上也体会不到电量的损耗. 然而, 对于用户来说, 实际上App的电量损耗也是用户体验的一个...

    引言

    电量使用优化, 基本上是我们最不怎么关注的一项优化. 可能很多公司连QA/Tester也不会关注测试App电量的使用. 一般来说开发和测试的测试设备也一直是连着USB处于充电状态的, 感官上也体会不到电量的损耗.

    然而, 对于用户来说, 实际上App的电量损耗也是用户体验的一个方面. 特别是当今人们对移动设备的依赖度越来越高, 电量也是用户特别关注的.

    今天我们就来聊聊Android App的电量优化.

    1, 分析电量的使用情况

    1.1 Batterystats & bugreport

    Android 5.0及以上的设备, 允许我们通过adb命令dump出电量使用统计信息.

    1, 因为电量统计数据是持续的, 会非常大, 统计我们的待测试App之前先reset下, 连上设备, 命令行执行:

    $ adb shell dumpsys batterystats --reset
    Battery stats reset.
    

    2, 断开测试设备, 操作我们的待测试App.
    3, 重新连接设备, 使用adb命令导出相关统计数据:

    // 此命令持续记录输出, 想要停止记录时按Ctrl+C退出.
    $ adb bugreport > bugreport.txt
    

    导出的统计数据存储到bugreport.txt, 此时我们可以借助如下工具来图形化展示电池的消耗情况.

    注意, 官方SDK文档导出文件方式为:
    adb shell dumpsys batterystats > batterystats.txt
    使用python historian.py batterystats.txt > batterystats.html查看数据
    是battery-historian老版本的使用方式. 目前Battery Historian已更新2.0版本, 推荐使用bugreport方式导出数据分析, 可以看到更多信息.

    1.2 Battery Historian

    Google提供了一个开源的电池历史数据分析工具 – Battery Historian.

    1.2.1 安装

    按照Battery Historian在github上的readme, 一步步安装即可.

    需要注意的是, Battery Historian是Go语言的, 安装Go的时候需要配置其bin的环境变量.
    Python环境需要是2.7的(3.x不行), 建议使用pyenv管理本地的python环境.
    另外, 因为Battery Historian是一个网页版工具, 涉及一些JS引用, 有时需要翻墙.

    安装完成后, 执行:

    cd $GOPATH/src/github.com/google/battery-historian
    go run cmd/battery-historian/battery-historian.go [--port <default:9999>]
    

    程序运行在http://localhost:9999, 如下:
    在这里插入图片描述
    1.2.2 界面

    导入我们在第一步通过adb bugreport生成的bugreport.txt文件:
    在这里插入图片描述

    2, 主要的耗电因素

    在这里插入图片描述
    从手机的电池详情统计可以简单看出, 手机中最耗电的模块肯定是屏幕了, 接着就是网络相关, 另外可能的耗电大户还有GPS芯片, Camera等.

    对于一个App, 对应因素主要有:

    2.1 网络请求

    我们可能会有发现:

    • 测试用的手机充满电放了一个十一假期还有电, 是因为测试手机没有上SIM卡.
    • 飞行模式下的手机灭屏下, 可能可以放一个月都还有电.

    这是因为:

    • 手机的通过内置的射频模块和基站几乎, 从而链接上网的, 而这个射频模块(radio)是非常耗电的.
    • 为了控制这个射频模块的耗电, 硬件驱动及Android RIL层做了很多处理. 例如可以单独关闭radio(飞行模式),
      间歇性假休眠radio(有数据发生时才上电, 保持一个频率的与基站交互)等等.

    现如今App都是移动互联网App, 不可避免的会有大量的网络请求, 会导致radio一直处于活跃状态, 从而耗电量增加.

    2.2 WakeLock

    Android系统本身为了优化电量的使用, 会在没有操作时进入休眠状态, 来节省电量. 当然, 为了便于开发(很多应用不可避免的希望在灭屏后还能运行一些事儿, 或是要保持屏幕一直亮着–比如播放视频), Android提供了一个PowerManager.WakeLock的东西.

    我们可以用WakeLock来保持CPU运行, 或是防止屏幕变暗/关闭, 让手机可以在用户不操作时依然可以做一些事儿. 然而, 获取WakeLock很容易, 释放不好就会成为难题, 消耗电量.

    例如我们获取了一个WakeLock来保持CPU运转, 做一个复杂运算并将数据上传到后台服务器, 然后释放该WakeLock. 然而这个过程可能并不像我们想象的那么快, 可能因为比如服务器挂掉, 计算出了异常等等WakeLock没有释放. 问题就来了, CPU会一直得不到休眠, 而大大增加耗电.

    另外, WakeLock还有android:keepScreenOn属性, 还可以让屏幕常量, 这可是耗电大户.

    2.3 GPS

    应用中经常会用到定位服务, Android提供了Network定位和GPS定位. 相对来说, GPS会精确得多, 对于一些诸如跑步, 导航类的应用基本会使用GPS定位. 然而, GPS定位也会消耗大量的电量.

    3, 尽可能减少App的电量消耗的建议

    了解了上述的主要的耗电因素, 还有一些程序的耗电问题, 我们通过Battery Historian也可以分析.

    针对这些耗电情况, 给出如下优化建议:

    3.1 优化网络请求

    这个会在网络优化那篇中细聊, 在此略过.

    3.2 谨慎使用WakeLock

    1,WakeLock获取释放成对出现.
    2,使用超时WakeLock, 以防出异常导致没有释放.

    // Acquires the wake lock with a timeout.
    acquire(long timeout)
    

    3.3 监听手机充电状态

    BatteryManager会发送一个包含充电状态的持续广播, 我们可以通过此广播获取充电状态和电量详情:

    IntentFilter ifilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
    Intent batteryStatus = context.registerReceiver(null, ifilter);
    

    注意: 因为这是一个持续广播, 我们无需写receiver, 可以直接通过intent获取相关数据.

    例如, 如果设备正在充电:

    // Are we charging / charged?
    int status = batteryStatus.getIntExtra(BatteryManager.EXTRA_STATUS, -1);
    boolean isCharging = status == BatteryManager.BATTERY_STATUS_CHARGING ||
                         status == BatteryManager.BATTERY_STATUS_FULL;
    
    // How are we charging?
    int chargePlug = battery.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1);
    boolean usbCharge = chargePlug == BATTERY_PLUGGED_USB;
    boolean acCharge = chargePlug == BATTERY_PLUGGED_AC;
    

    另外我们也可以监听充电状态的变化, 只要设备连接或断开电源, BatteryManager就会广播相应的操作, 我们可以注册receiver来监听:

    <receiver android:name=".PowerConnectionReceiver">
      <intent-filter>
        <action android:name="android.intent.action.ACTION_POWER_CONNECTED"/>
        <action android:name="android.intent.action.ACTION_POWER_DISCONNECTED"/>
      </intent-filter>
    </receiver>
    

    监听电池状态, 可以让我们将一些操作放在充电或是电量足够的情况下进行, 以提升用户体验. 例如用户数据同步, Log上传等.

    3.4 Doze and App Standby

    Android 6.0提供了两个用来节省电量的技术Doze和App Standby.

    • Doze 瞌睡. 如果设备闲置了一段较长时间, Doze技术将通过延迟后台网络活动, CPU运行等来减少电量损耗.
    • App Standy 应用待机. 不是最近得到过用户"宠幸"的App, App Standy将延缓这个应用的后台网络活动.

    因为所有Android 6.0及以上的设备上, Doze and App Standby都会运行. 可能会影响你的App的运行, 具体的适配请参考官方文档.

    3.5 关于定位

    • 定位中使用GPS, 请记得及时关闭
    // Remove the listener you previously added
    locationManager.removeUpdates(locationListener);
    
    • 减少更新频率
    • 根据实际情况选择GPS或网络或两者. 只使用一个会降低电量损耗.
    展开全文
  • 如何测试Android APP的耗电量?,文中用adb的方式,bat脚本可以半自动化测试,实例参考,适用于新手入门
  • 大多数开发者在没有发现严重性能问题之前是不会...我们可以通过Android SDK里面提供的诸多工具来收集CPU、GPU、内存、电量等性能数据。 ·Insight:分析数据 通过上面的步骤,我们获取到了大量的数据,下一步就是分析这

    大多数开发者在没有发现严重性能问题之前是不会特别花精力去关注性能优化的,通常大家关注的都是功能是否实现。当性能问题真的出现的时候,请不要慌乱。我们通常采用下面三个步骤来解决性能问题。

    ·Gather:收集数据

    我们可以通过Android SDK里面提供的诸多工具来收集CPUGPU、内存、电量等性能数据。

    ·Insight:分析数据

    通过上面的步骤,我们获取到了大量的数据,下一步就是分析这些数据。工具帮我们生成了很多可读性强的表格,我们需要事先了解如何查看表格的数据,每一项代表的含义,这样才能够快速定位问题。如果分析数据之后还是没有找到问题,那么就只能不停的重新收集数据,再进行分析,如此循环。

    ·Action:解决问题

    定位到问题之后,我们需要采取行动来解决问题。解决问题之前一定要先有个计划,评估这个解决方案是否可行,是否能够及时的解决问题。

     

    一般情况下,数据分析可以得到一些功能模块的速度达不到要求或者电量消耗过大,这种情况下就得加快速度与减少耗电量,至于加快速度与减少耗电量的具体方案的根据具体功能模块具体定。常见的需要提速的模块主要有网络请求,数据库操作等,解决办法包括使用cache,缓存,预加载,延迟获取,减少冗余数据等手段,当然也可以使用开源框架。对于提速相关优化,在其他文章中已经说得很多了,这里就说明写电量优化,如下就是一种电量优化方案

    关于Batching下面使用一张图演示下Batching的原理(将单次的网络请求变成批量的,这样可以减少每次请求开启网络的电量损耗):

     

     

     

    Service性能优化

    ServiceAndroid程序里面最常用的基础组件之一,但是使用Service很容易引起电量的过度消耗以及系统资源的未及时释放。学会在何时启用Service以及使用何种方式杀掉Service就显得十分有必要了。

    简要过一下Service的特性:ServiceUI没有关联,Service的创建,执行,销毁Service都是需要占用系统时间和内存的。另外Service是默认运行在UI线程的,这意味着Service可能会影响到系统的流畅度。

    使用Service应该遵循下面的一些规则:

    ·避免错误的使用Service,例如我们不应该使用Service来监听某些事件的变化,不应该搞一个Service在后台对服务器不断的进行轮询(应该使用Google Cloud Messaging)

    ·如果已经事先知道Service里面的任务应该执行在后台线程(非默认的主线程)的时候,我们应该使用IntentService或者结合HanderThreadAsycnTask Loader实现的Service

    Android系统为我们提供了以下的一些异步相关的工具类

    ·GCM

    ·BroadcastReciever

    ·LocalBroadcastReciever

    ·WakefulBroadcastReciver

    ·HandlerThreads

    ·AsyncTaskLoaders

    ·IntentService

    如果使用上面的诸多方案还是无法替代普通的Service,那么需要注意的就是如何正确的关闭Service

    ·普通的Started Service,需要通过stopSelf()来停止Service

     

    ·另外一种Bound Service,会在其他组件都unBind之后自动关闭自己

     

    把上面两种Service进行合并之后,我们可以得到如下图所示的

     


    结语:最近一直在处理的Android App优化博客到现在已经暂时该一段落了,这段时间笔者从速度,内存,电量等方面说明了,优化方法,希望各位能再看我博客时有所得。

    展开全文
  • 很多应用在电量过低的情况下会出现问题, 特别是一些和硬件相关的应用,譬如相机,播放器等应用。 之前在碰到过在电量5%的情况下开闪光灯拍照拉低电压导致系统直接死机…… 那么如何来解决这类问题呢? 其实在...

    很多应用在电量过低的情况下会出现问题,

    特别是一些和硬件相关的应用,譬如相机,播放器等应用。

    之前在碰到过在电量5%的情况下开闪光灯拍照拉低电压导致系统直接死机……

    那么如何来解决这类问题呢?

    其实在系统服务中当电量发生变化时,会发出广播 ACTION_BATTERY_CHANGED

    在 App 中写一个广播接收器,并注册上,就可以接收到电量变化的消息了,当电量达到一定的值时,就可以采取措施,

    譬如提示用户电量过低,将要退出应用等,

    或者一些正在操作的任务,譬如正在玩游戏等,可以提示用户电量不足,保存相关信息等

    正在进行录像的话,则可以直接停止并保存录相。

        private final BroadcastReceiver batteryReceiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                String action = intent.getAction();
                int mBatteryLevel;
                if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
                    Log.d(TAG, "batteryReceiver ACTION_BATTERY_CHANGED");
                    int level = intent.getIntExtra("level", 0);
                    int scale = intent.getIntExtra("scale", 100);
                    synchronized (this) {
                        mBatteryLevel = level * 100 / scale;
                    }
                    Log.d(TAG, "mBatteryLevel = " + mBatteryLevel + " %");
                    Log.d(TAG, "mExitLowPower = " + mExitLowPower);
                    if (mBatteryLevel <= 4 && !mExitLowPower) {
                        showBatteryLowAndFinish();
    					Log.v(TAG,"low power mCameraState "+mCameraState);
    					if((mCameraState == STATE_RECORDING_IN_PROGRESS)
    						&& (mCameraActor instanceof VideoActor)){
    						Log.v(TAG,"batteryReceiver videoActor");
    						mCameraActor.stopActor();
    					}
                        exitCameraAwhileWhenLowPower();
                    } else if (mBatteryLevel > 4){
                        mExitLowPower = false;
                    }
                }
            }
        };

    这里判断当电量低于 4% 时,则直接退出应用并保存录像。其它应用跟据需要可以采取别的措施!
    展开全文
  • 这是一篇讲述应用耗电的文章,围绕 Android 电量采集机制及第二代 Battery Historian 分析工具讲述。文从数据采集、导出、环境搭建、解读报告的角度出发,从细节讲解整个流程。和大谈概念的文章不同,这里将进行实际...
  • Android App耗电量测试

    2019-08-09 17:51:29
    耗电量测试是指测试App在运行过程中消耗的能量。 设备运行期间消耗能量公式:W = w * t = U * I * t U为电池供电电压,I为电流值,t为测试时间,通常来说U可以认为不变,因此A = I * t (mAh)可以作为消耗能量的值,...
  • Android APP耗电优化可能造成耗电的一些原因网络请求耗电,而且手机数据网络进行http请求比无线网进行http请求更加耗电,因为数据网络调用到一些底层的硬件模块,就如GPS一样,当手机打开GPS功能后,也是启动了一些...
  • Android统计App耗电量比较麻烦,直至Android 4.4,它仍没公开“电量统计”API或文档……额,是的,仅没有公开,并不是没有。平时在手机“设置- 电量”看到的数据就是系统调用内部API的统计结果。
  • 方法: 手机自带的电量监控、GT 命令(5.0以上系统才可以):
  • 该工具主要用来监控app的耗电数据,方便了解自己app电量耗费情况,以及方便跟竞品进行对比~一、该工具使用环境:需要安装JDK和SDK,并且配置环境变量才可使用;测试设备安卓系统要&gt;=5.0系统以上二、通过adb...
  • Android电池电量使用详情查看 关于Android电量的基础知识 关于电能的相关物理公式 电功率公式P=UI,P为电功率单位为w(瓦),U为电压单位V(伏特),I为电流单位安(A) 电能公式W=Pt=UIt,W为电能单位j(焦耳)...
  • Android App性能测试白皮书 | 流量、电量、弱网环境怎么测?作者:张宇 来源:百度QA 2017-01-16 132957干货分享背景介绍Android用户也许会经常碰到以下的问题:1)应用后台开着,手机很快没电了——应用耗电大;2)...
  • 监测电量和充电状态... 1 确定当前充电状态... 1 监测充电状态变化... 1 确定当前电量水平... 2 监测电量的重要变化... 2   监测电量和充电状态 当你调整后台更新的频率以降低频繁更新导致电池老化的问题时...
  • Android App优化之性能分析工具Android App优化之提升你的App启动速度之理论基础Android App优化之提升你的App启动速度之实例挑战Android App...之消除卡顿Android App优化之内存优化Android App优化之持久电量A
  • Android App优化之性能分析工具Android App优化之提升你的App启动速度之理论基础Android App优化之提升你的App启动速度之实例挑战Android App优化之Layout怎么摆Android App优化之ANR详解Android App优化之消除卡顿...
  • 记录电量消耗本身也是一个费电量的事情,随着Android开的性能要求越来越高,电量的优化,也显得格外重要,一个耗电的应用,用户肯定会毫不犹豫的进行卸载,所以本篇博客,我们一起来学习Android性能优化之电量优化。...
  • Android电量优化

    2016-05-06 16:27:29
    android电量消耗分析,优化,android6.0-doze模式app standby
1 2 3 4 5 ... 20
收藏数 16,851
精华内容 6,740