Android 耗电量统计原理剖析

在android系统中,耗电量排行一直是一个实用的功能
Android 耗电量排行
当我们点击了电池用量后,就可以到达详细信息的界面。
耗电量详细信息
在这个界面中,我们可以看到对于电池使用时间的预测。
可以看到具体app的使用耗电量排行。那么系统的是怎么实现的呢?
注意右上角的“显示完整的设备用电量”

在这里插入图片描述
当我们点击之后,就可以看到系统完整的耗电量排行。
在这里插入图片描述
可以看到,Android操作系统,屏幕等系统的信息也都显示了出来。
那么这个功能是怎么实现的呢?
我们来一一分析。

主要的功能结构如下:
- 电池用量信息变化
- 使用时间预测
- 应用与系统耗电量排行


1. 电池用量信息变化

电池用量的接口是在PowerUsageSummary中定义的,menu.add直接在代码中动态的添加了MENU_ADVANCED_BATTERY

    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
        if (DEBUG) {
            menu.add(Menu.NONE, MENU_STATS_TYPE, Menu.NONE, R.string.menu_stats_total)
                    .setIcon(com.android.internal.R.drawable.ic_menu_info_details)
                    .setAlphabeticShortcut('t');
        }

        menu.add(Menu.NONE, MENU_ADVANCED_BATTERY, Menu.NONE, R.string.advanced_battery_title);

        super.onCreateOptionsMenu(menu, inflater);
    }

当点击了这个menu后,就会跳入到了options item select的函数中。对应的处理是MENU_ADVANCED_BATTERY

    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case MENU_STATS_TYPE:
                if (mStatsType == BatteryStats.STATS_SINCE_CHARGED) {
                    mStatsType = BatteryStats.STATS_SINCE_UNPLUGGED;
                } else {
                    mStatsType = BatteryStats.STATS_SINCE_CHARGED;
                }
                refreshUi(BatteryUpdateType.MANUAL);
                return true;
            case MENU_ADVANCED_BATTERY:
                new SubSettingLauncher(getContext())
                        .setDestination(PowerUsageAdvanced.class.getName())
                        .setSourceMetricsCategory(getMetricsCategory())
                        .setTitle(R.string.advanced_battery_title)
                        .launch();
                return true;
            default:
                return super.onOptionsItemSelected(item);
        }
    }

会去启动电池用量的专属类PowerUsageAdvanced
PowerUsageAdvanced的构造函数中,首先声明了对于这个界面布局的初始化。调用的布局为:

<PreferenceScreen
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:settings="http://schemas.android.com/apk/res-auto"
    android:key="power_usage_advanced_screen"
    android:title="@string/advanced_battery_title"
    settings:keywords="@string/keywords_battery">

    <com.android.settings.fuelgauge.BatteryHistoryPreference
        android:key="battery_graph"/>

    <PreferenceCategory
        android:key="app_list"
        android:title="@string/power_usage_list_summary"/>

</PreferenceScreen>

这个布局中的三个key为:power_usage_advanced_screen,battery_graph,app_list。
power_usage_advanced_screen为整个xml的布局,在其他文件中并未引用。
battery_graph被引用是在

    @Override
    public void onCreate(Bundle icicle) {
        super.onCreate(icicle);
        final Context context = getContext();

        mHistPref = (BatteryHistoryPreference) findPreference(KEY_BATTERY_GRAPH);
        mPowerUsageFeatureProvider = FeatureFactory.getFactory(context)
                .getPowerUsageFeatureProvider(context);
        mBatteryUtils = BatteryUtils.getInstance(context);

        // init the summary so other preferences won't have unnecessary move
        updateHistPrefSummary(context);
        restoreSavedInstance(icicle);
    }

mHistPref初始化了这个preference,并且将其声明为了是一个BatteryHistoryPreference的对象。
这个对象的使用是在refreshUI中进行使用的。

    @Override
    protected void refreshUi(@BatteryUpdateType int refreshType) {
        final Context context = getContext();
        if (context == null) {
            return;
        }
        updatePreference(mHistPref);
        updateHistPrefSummary(context);

        mBatteryAppListPreferenceController.refreshAppListGroup(mStatsHelper, mShowAllApps);
    }

那么这个refreshUI是在哪边被调用的呢?
refreshUI是定义在PowerUsageBase中的一个abstract function。是在PowerLoaderCallback中使用。

    /**
     * {@link android.app.LoaderManager.LoaderCallbacks} for {@link PowerUsageBase} to load
     * the {@link BatteryStatsHelper}
     */
    public class PowerLoaderCallback implements LoaderManager.LoaderCallbacks<BatteryStatsHelper> {
        private int mRefreshType;

        @Override
        public Loader<BatteryStatsHelper> onCreateLoader(int id,
                Bundle args) {
            mRefreshType = args.getInt(KEY_REFRESH_TYPE);
            return new BatteryStatsHelperLoader(getContext());
        }

        @Override
        public void onLoadFinished(Loader<BatteryStatsHelper> loader,
                BatteryStatsHelper statsHelper) {
            mStatsHelper = statsHelper;
            refreshUi(mRefreshType);
        }

        @Override
        public void onLoaderReset(Loader<BatteryStatsHelper> loader) {

        }
    }

PowerLoaderCallback是对LoaderManager.LoaderCallbacks<BatteryStatsHelper>的一个实现。
而BatteryStatsHelper类用于负责计算各个应用和服务的电量使用情况。
在进入settings和发生点亮改变的时候,会去刷新这个值。
可以看到这个callback的初始化是在

protected void restartBatteryStatsLoader(int refreshType) {
        final Bundle bundle = new Bundle();
        bundle.putInt(KEY_REFRESH_TYPE, refreshType);

        getLoaderManager().restartLoader(0, bundle, new PowerLoaderCallback());
    }

而restartBatteryStatsLoader的调用主要有两处地方:

  1. 是在PowerUsageBase中,
    @Override
    public void onCreate(Bundle icicle) {
        super.onCreate(icicle);
        mStatsHelper.create(icicle);
        setHasOptionsMenu(true);

        mBatteryBroadcastReceiver = new BatteryBroadcastReceiver(getContext());
        mBatteryBroadcastReceiver.setBatteryChangedListener(type -> {
            restartBatteryStatsLoader(type);
        });
    }
  1. 是在PowerUsageAdvanced中,
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case MENU_TOGGLE_APPS:
                mShowAllApps = !mShowAllApps;
                item.setTitle(mShowAllApps ? R.string.hide_extra_apps : R.string.show_all_apps);
                mMetricsFeatureProvider.action(getContext(),
                        MetricsProto.MetricsEvent.ACTION_SETTINGS_MENU_BATTERY_APPS_TOGGLE,
                        mShowAllApps);
                restartBatteryStatsLoader(BatteryUpdateType.MANUAL);
                return true;
            default:
                return super.onOptionsItemSelected(item);
        }
    }

我们先来分析第一种调用,第一种调用是在oncreate的函数中初始化了BatteryBroadcastReceiver,并且设置了listener。
在onResume中对这个listener进行了注册。

第二种的调用是在显示all app还是extra app的时候,进行restart,来进行状态的更新。

看完了refreshUI的调用,那我们来看下refreshUI的实现。
updatePreference

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值