在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
的构造函数中,首先声明了对于这个界面布局的初始化。调用的布局为:
这个布局中的三个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 {
private int mRefreshType;
@Override
public Loader onCreateLoader(int id,
Bundle args) {
mRefreshType = args.getInt(KEY_REFRESH_TYPE);
return new BatteryStatsHelperLoader(getContext());
}
@Override
public void onLoadFinished(Loader loader,
BatteryStatsHelper statsHelper) {
mStatsHelper = statsHelper;
refreshUi(mRefreshType);
}
@Override
public void onLoaderReset(Loader loader) {
}
}
PowerLoaderCallback是对LoaderManager.LoaderCallbacks
而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的调用主要有两处地方:
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
mStatsHelper.create(icicle);
setHasOptionsMenu(true);
mBatteryBroadcastReceiver = new BatteryBroadcastReceiver(getContext());
mBatteryBroadcastReceiver.setBatteryChangedListener(type -> {
restartBatteryStatsLoader(type);
});
}
@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