@@ -36,12 +36,9 @@ import cc.winboll.studio.libappbase.LogUtils;
public class BatteryReportActivity extends Activity {
public class BatteryReportActivity extends Activity {
public static final String TAG = " BatteryReportActivity " ;
public static final String TAG = " BatteryReportActivity " ;
// 目标应用包名常量(统一维护,数据计算核心标识)
private static final String TARGET_APP_PACKAGE = " cc.winboll.studio.mymessagemanager " ;
private RecyclerView rvBatteryReport ;
private RecyclerView rvBatteryReport ;
private BatteryReportAdapter adapter ;
private BatteryReportAdapter adapter ;
// 数据列表:仅存储包名、耗电、时长(不存储名称,计算全程用包名)
private List < AppBatteryModel > dataList = new ArrayList < AppBatteryModel > ( ) ;
private List < AppBatteryModel > dataList = new ArrayList < AppBatteryModel > ( ) ;
private List < AppBatteryModel > filteredList = new ArrayList < AppBatteryModel > ( ) ;
private List < AppBatteryModel > filteredList = new ArrayList < AppBatteryModel > ( ) ;
private BroadcastReceiver batteryReceiver ;
private BroadcastReceiver batteryReceiver ;
@@ -49,16 +46,14 @@ public class BatteryReportActivity extends Activity {
private float lastBatteryPercent = 100 . 0f ;
private float lastBatteryPercent = 100 . 0f ;
private long lastCheckTime = System . currentTimeMillis ( ) ;
private long lastCheckTime = System . currentTimeMillis ( ) ;
private EditText etSearch ;
private EditText etSearch ;
// 应用运行时长缓存( key: 包名, value: 时长ms)
private Map < String , Long > appRunTimeCache = new HashMap < String , Long > ( ) ;
private Map < String , Long > appRunTimeCache = new HashMap < String , Long > ( ) ;
// 包管理工具(全局持有,避免重复获取)
private Map < String , String > packageToAppNameCache = new HashMap < String , String > ( ) ;
private PackageManager mPackageManager ;
private PackageManager mPackageManager ;
@Override
@Override
protected void onCreate ( Bundle savedInstanceState ) {
protected void onCreate ( Bundle savedInstanceState ) {
super . onCreate ( savedInstanceState ) ;
super . onCreate ( savedInstanceState ) ;
setContentView ( R . layout . activity_batteryreport ) ;
setContentView ( R . layout . activity_battery_ report ) ;
// 初始化包管理工具(仅一次,供后续查询名称使用)
mPackageManager = getPackageManager ( ) ;
mPackageManager = getPackageManager ( ) ;
// 权限检查( Java7 传统条件判断)
// 权限检查( Java7 传统条件判断)
@@ -72,34 +67,31 @@ public class BatteryReportActivity extends Activity {
rvBatteryReport = ( RecyclerView ) findViewById ( R . id . rv_battery_report ) ;
rvBatteryReport = ( RecyclerView ) findViewById ( R . id . rv_battery_report ) ;
rvBatteryReport . setLayoutManager ( new LinearLayoutManager ( this ) ) ;
rvBatteryReport . setLayoutManager ( new LinearLayoutManager ( this ) ) ;
// 1. 加载所有应用(仅存包名,不查名称)
// 初始化流程: 新增“加载24小时累计耗电”步骤
loadAllAppPackage ( ) ;
loadAllAppPackage ( ) ;
// 2. 强制添加目标应用(包名兜底)
preCacheAllAppNames ( ) ;
//forceAddTargetPackage();
// 3. 首次获取运行时长( key: 包名)
appRunTimeCache = getAppRunTime ( ) ;
appRunTimeCache = getAppRunTime ( ) ;
// 4. 更新时长到数据模型(用包名匹配)
updateAppRunTimeToModel ( ) ;
updateAppRunTimeToModel ( ) ;
// 5. 初始化过滤列表和适配器(传入包管理工具供显示时查名称)
calculateInitial24hTotalConsumption ( ) ; // 初始化时计算24小时累计耗电
filteredList . addAll ( dataList ) ;
filteredList . addAll ( dataList ) ;
adapter = new BatteryReportAdapter ( this , filteredList , mPackageManager ) ;
adapter = new BatteryReportAdapter ( this , filteredList , mPackageManager , packageToAppNameCache );
rvBatteryReport . setAdapter ( adapter ) ;
rvBatteryReport . setAdapter ( adapter ) ;
// 搜索监听(按包名过滤,不涉及名称 )
// 搜索监听(不变 )
etSearch . addTextChangedListener ( new TextWatcher ( ) {
etSearch . addTextChangedListener ( new TextWatcher ( ) {
@Override
@Override
public void beforeTextChanged ( CharSequence s , int start , int count , int after ) { }
public void beforeTextChanged ( CharSequence s , int start , int count , int after ) { }
@Override
@Override
public void onTextChanged ( CharSequence s , int start , int before , int count ) {
public void onTextChanged ( CharSequence s , int start , int before , int count ) {
filterAppsByPackage ( s . toString ( ) ) ;
filterAppsByPackageAndName ( s . toString ( ) ) ;
}
}
@Override
@Override
public void afterTextChanged ( Editable s ) { }
public void afterTextChanged ( Editable s ) { }
} ) ;
} ) ;
// 电池广播(耗电计算全程用包名)
// 电池广播:调用修改后的“单次耗电计算+累计累加”方法
batteryReceiver = new BroadcastReceiver ( ) {
batteryReceiver = new BroadcastReceiver ( ) {
@Override
@Override
public void onReceive ( Context context , Intent intent ) {
public void onReceive ( Context context , Intent intent ) {
@@ -108,17 +100,13 @@ public class BatteryReportActivity extends Activity {
float currentPercent = ( float ) level / scale * 100 ;
float currentPercent = ( float ) level / scale * 100 ;
LogUtils . d ( TAG , " 电池百分比变化: " + lastBatteryPercent + " -> " + currentPercent ) ;
LogUtils . d ( TAG , " 电池百分比变化: " + lastBatteryPercent + " -> " + currentPercent ) ;
// 计算电池消耗并更新数据(全程用包名)
if ( currentPercent < lastBatteryPercent ) {
if ( currentPercent < lastBatteryPercent ) {
float dropPercent = lastBatteryPercent - currentPercent ;
float dropPercent = lastBatteryPercent - currentPercent ;
long duration = System . currentTimeMillis ( ) - lastCheckTime ;
long duration = System . currentTimeMillis ( ) - lastCheckTime ;
LogUtils . d ( TAG , " 电池消耗: " + dropPercent + " %,时长: " + duration + " ms " ) ;
LogUtils . d ( TAG , " 电池消耗: " + dropPercent + " %,时长: " + duration + " ms " ) ;
// 重新获取最新运行时长( key: 包名)
appRunTimeCache = getAppRunTime ( ) ;
appRunTimeCache = getAppRunTime ( ) ;
// 更新模型中的运行时长(包名匹配)
updateAppRunTimeToModel ( ) ;
updateAppRunTimeToModel ( ) ;
// 分配耗电(包名计算)
calculateSingleConsumptionAndAccumulate ( dropPercent , appRunTimeCache ) ; // 单次+累计逻辑
distributeBatteryConsumption ( dropPercent , appRunTimeCache ) ;
}
}
lastBatteryPercent = currentPercent ;
lastBatteryPercent = currentPercent ;
@@ -138,125 +126,165 @@ public class BatteryReportActivity extends Activity {
}
}
/**
/**
* 加载所有应用(仅获取包名,不查询应用名称,数据计算核心步骤 )
* 加载所有应用(仅获取包名,初始化模型时单次耗电、累计耗电均设为0 )
*/
*/
private void loadAllAppPackage ( ) {
private void loadAllAppPackage ( ) {
List < ApplicationInfo > appList = mPackageManager . getInstalledApplications ( PackageManager . GET_META_DATA ) ;
List < ApplicationInfo > appList = mPackageManager . getInstalledApplications ( PackageManager . GET_META_DATA ) ;
dataList . clear ( ) ; // 清空列表避免重复
dataList . clear ( ) ;
LogUtils . d ( TAG , " 开始加载应用包名列表,共找到 " + appList . size ( ) + " 个应用 " ) ;
LogUtils . d ( TAG , " 开始加载应用包名列表,共找到 " + appList . size ( ) + " 个应用 " ) ;
// 仅遍历包名,不处理名称(避免名称获取异常影响)
for ( ApplicationInfo appInfo : appList ) {
for ( ApplicationInfo appInfo : appList ) {
String packageName = appInfo . packageName ;
String packageName = appInfo . packageName ;
/*if (packageName.equals("cc.winboll.studio.powerbell.beta")) {
// 初始化: 单次耗电( consumption) =0, 累计耗电( totalConsumption) =0, 运行时长=0
//if (packageName.equals("aidepro.top")) {
dataList . add ( new AppBatteryModel ( packageName , 0 . 0f , 0 . 0f , 0 ) ) ;
LogUtils.d(TAG, "aidepro.top OK5");
}*/
// 模型仅存包名、初始耗电0、初始时长0( 名称显示时再查)
dataList . add ( new AppBatteryModel ( packageName , " 0.0 " , 0 ) ) ;
}
}
/*for (AppBatteryModel appBatteryModel : dataList) {
if (appBatteryModel.getPackageName().equals("aidepro.top")) {
LogUtils.d(TAG, "aidepro.top OK4");
}
}*/
LogUtils . d ( TAG , " 应用包名列表加载完成,共添加 " + dataList . size ( ) + " 个包名。 " ) ;
LogUtils . d ( TAG , " 应用包名列表加载完成,共添加 " + dataList . size ( ) + " 个包名。 " ) ;
}
}
/**
/**
* 强制添加目标包名(兜底逻辑,仅操作包名 )
* 预缓存应用名称(逻辑不变 )
*/
*/
private void forceAddTargetPackage ( ) {
private void preCacheAllAppNames ( ) {
// 1. 先检查列表中是否已存在目标包名
packageToAppNameCache . clear ( ) ;
boolean isTargetExists = false ;
LogUtils . d ( TAG , " 开始预缓存包名-应用名称映射 " ) ;
for ( AppBatteryModel model : dataList ) {
if ( TARGET_APP_PACKAGE . equals ( model . getPackageName ( ) ) ) {
isTargetExists = true ;
break ;
}
}
if ( isTargetExists ) {
LogUtils . d ( TAG , " 目标包名已在列表中,无需重复添加 " ) ;
return ;
}
// 2. 仅用包名创建模型,强制添加(不依赖名称查询)
dataList . add ( 0 , new AppBatteryModel ( TARGET_APP_PACKAGE , " 0.0 " , 0 ) ) ;
LogUtils . d ( TAG , " 强制添加目标包名成功: " + TARGET_APP_PACKAGE ) ;
}
/**
* 更新运行时长到模型(用包名匹配,不涉及名称)
*/
private void updateAppRunTimeToModel ( ) {
/*if(appRunTimeCache.containsKey("aidepro.top"))
{
LogUtils.d(TAG, "aidepro.top OK2");
}*/
int nCount = 0 ;
for ( AppBatteryModel model : dataList ) {
for ( AppBatteryModel model : dataList ) {
String packageName = model . getPackageName ( ) ;
String packageName = model . getPackageName ( ) ;
/*if(packageName.equals("aidepro.top"))
String appName = getAppNameByPackage ( packageName ) ;
{
packageToAppNameCache . put ( packageName , appName ) ;
LogUtils.d(TAG, "aidepro.top OK3");
}
}*/
LogUtils . d ( TAG , " 预缓存完成,共缓存 " + packageToAppNameCache . size ( ) + " 个应用名称 " ) ;
}
/**
* 通过包名获取应用名称(逻辑不变)
*/
private String getAppNameByPackage ( String packageName ) {
try {
ApplicationInfo appInfo = mPackageManager . getApplicationInfo ( packageName , 0 ) ;
return mPackageManager . getApplicationLabel ( appInfo ) . toString ( ) ;
} catch ( PackageManager . NameNotFoundException e ) {
LogUtils . e ( TAG , " 包名 " + packageName + " 对应的应用未找到: " + e . getMessage ( ) ) ;
return packageName ;
} catch ( Exception e ) {
LogUtils . e ( TAG , " 查询应用名称失败(包名: " + packageName + " ) : " + e . getMessage ( ) ) ;
return packageName ;
}
}
/**
* 更新运行时长到模型(逻辑不变)
*/
private void updateAppRunTimeToModel ( ) {
int nCount = 0 ;
for ( AppBatteryModel model : dataList ) {
String packageName = model . getPackageName ( ) ;
Long runTime ;
Long runTime ;
// Java7 显式判断包名是否在缓存中
if ( appRunTimeCache . containsKey ( packageName ) ) {
if ( appRunTimeCache . containsKey ( packageName ) ) {
/*if(packageName.equals("cc.winboll.studio.powerbell.beta")) {
LogUtils.d(TAG, String.format("特殊查询 %s 查询有结果。", packageName));
}*/
runTime = appRunTimeCache . get ( packageName ) ;
runTime = appRunTimeCache . get ( packageName ) ;
LogUtils . d ( TAG , String . format ( " 应用包 %s 运行时长已更新。 " , packageName ) ) ;
LogUtils . d ( TAG , String . format ( " 应用包 %s 运行时长已更新。 " , packageName ) ) ;
nCount + + ;
nCount + + ;
} else {
} else {
runTime = 0L ;
runTime = 0L ;
}
}
model . setRunTime ( runTime ) ;
model . setRunTime ( runTime ) ;
}
}
LogUtils . d ( TAG , String . format ( " dataList.size() %d, appRunTimeCache.size() %d。 " , dataList . size ( ) , appRunTimeCache . size ( ) ) ) ;
LogUtils . d ( TAG , String . format ( " dataList.size() %d, appRunTimeCache.size() %d。 " , dataList . size ( ) , appRunTimeCache . size ( ) ) ) ;
LogUtils . d ( TAG , String . format ( " updateAppRunTimeToModel() 更新的数据量为:%d " , nCount ) ) ;
LogUtils . d ( TAG , String . format ( " updateAppRunTimeToModel() 更新的数据量为:%d " , nCount ) ) ;
}
}
/**
/**
* 按包名过滤应用(搜索逻辑仅操作包名 )
* 【新增】初始化时计算24小时累计耗电( 赋值给totalConsumption )
* 逻辑: 基于24小时运行时长占比, 分配当前电池容量的理论24小时消耗
*/
*/
private void filterAppsByPackage ( String keyword ) {
private void calculateInitial24hTotalConsumption ( ) {
long total24hRunTime = 0 ;
// 1. 计算24小时内所有应用总运行时长
for ( Map . Entry < String , Long > entry : appRunTimeCache . entrySet ( ) ) {
total24hRunTime + = entry . getValue ( ) ;
}
LogUtils . d ( TAG , " 24小时内所有应用总运行时长: " + formatRunTime ( total24hRunTime ) ) ;
// 2. 按运行时长占比分配24小时累计耗电( 假设电池满电循环, 用总容量近似24小时总消耗)
for ( AppBatteryModel model : dataList ) {
String packageName = model . getPackageName ( ) ;
Long app24hRunTime = appRunTimeCache . getOrDefault ( packageName , 0L ) ;
// 计算占比与累计耗电
float ratio = ( total24hRunTime > 0 ) ? ( float ) app24hRunTime / total24hRunTime : 0 ;
float initialTotalConsumption = batteryCapacity * ratio ; // 用电池容量近似24小时总消耗
model . setTotalConsumption ( initialTotalConsumption ) ; // 初始化累计耗电
LogUtils . d ( TAG , String . format ( " 应用包 %s 24小时累计耗电初始化: %.1f mAh " , packageName , initialTotalConsumption ) ) ;
}
}
/**
* 【核心修改】计算单次耗电( 赋值给consumption) + 累加至累计耗电( totalConsumption = totalConsumption + consumption)
*/
private void calculateSingleConsumptionAndAccumulate ( float dropPercent , Map < String , Long > runTimeMap ) {
long totalSingleRunTime = 0 ;
// 1. 计算本次电池下降期间的总运行时长
for ( Map . Entry < String , Long > entry : runTimeMap . entrySet ( ) ) {
totalSingleRunTime + = entry . getValue ( ) ;
}
// 2. 遍历计算每个应用的“单次耗电”并“累加至累计”
for ( AppBatteryModel model : dataList ) {
String packageName = model . getPackageName ( ) ;
Long appSingleRunTime = runTimeMap . getOrDefault ( packageName , 0L ) ;
// 步骤1: 计算本次单次耗电( 赋值给consumption)
float ratio = ( totalSingleRunTime > 0 ) ? ( float ) appSingleRunTime / totalSingleRunTime : 0 ;
float singleConsumption = batteryCapacity * dropPercent / 100 * ratio ; // 单次消耗
model . setConsumption ( singleConsumption ) ; // 存储单次耗电
// 步骤2: 累加单次耗电到累计耗电( totalConsumption = 原有累计 + 本次单次)
float newTotalConsumption = model . getTotalConsumption ( ) + singleConsumption ;
model . setTotalConsumption ( newTotalConsumption ) ; // 更新累计耗电
// 同步运行时长
model . setRunTime ( appSingleRunTime ) ;
LogUtils . d ( TAG , String . format ( " 应用包 %s: 单次耗电%.1f mAh, 累计耗电%.1f mAh " ,
packageName , singleConsumption , newTotalConsumption ) ) ;
}
// 3. 按累计耗电排序(从高到低)
Collections . sort ( dataList , new Comparator < AppBatteryModel > ( ) {
@Override
public int compare ( AppBatteryModel m1 , AppBatteryModel m2 ) {
return Float . compare ( m2 . getTotalConsumption ( ) , m1 . getTotalConsumption ( ) ) ;
}
} ) ;
// 4. 重新应用过滤并刷新列表
filterAppsByPackageAndName ( etSearch . getText ( ) . toString ( ) ) ;
}
/**
* 双维度过滤(逻辑不变)
*/
private void filterAppsByPackageAndName ( String keyword ) {
filteredList . clear ( ) ;
filteredList . clear ( ) ;
if ( keyword = = null | | keyword . isEmpty ( ) ) {
if ( keyword = = null | | keyword . isEmpty ( ) ) {
filteredList . addAll ( dataList ) ;
filteredList . addAll ( dataList ) ;
} else {
} else {
String lowerKeyword = keyword . toLowerCase ( ) ;
String lowerKeyword = keyword . toLowerCase ( ) ;
boolean isTargetMatched = false ;
for ( AppBatteryModel model : dataList ) {
for ( AppBatteryModel model : dataList ) {
String packageNameLower = model . getPackageName ( ) . toLowerCase ( ) ;
String packageName = model . getPackageName ( ) ;
// 仅按包名包含关键词过滤
String packageNameLower = packageName . toLowerCase ( ) ;
boolean isMatched = packageNameLower . contains ( lowerKeyword ) ;
String appName = packageToAppNameCache . get ( packageName ) ;
String appNameLower = appName . toLowerCase ( ) ;
boolean isMatched = packageNameLower . contains ( lowerKeyword )
| | appNameLower . contains ( lowerKeyword ) ;
if ( isMatched ) {
if ( isMatched ) {
filteredList . add ( model ) ;
filteredList . add ( model ) ;
// 检查是否是目标包名
if ( TARGET_APP_PACKAGE . equals ( model . getPackageName ( ) ) ) {
isTargetMatched = true ;
}
}
}
// 兜底:目标包名未匹配时强制添加
if ( ! isTargetMatched ) {
for ( AppBatteryModel model : dataList ) {
if ( TARGET_APP_PACKAGE . equals ( model . getPackageName ( ) ) ) {
filteredList . add ( 0 , model ) ;
LogUtils . d ( TAG , " 搜索兜底:强制添加目标包名到结果列表 " ) ;
break ;
}
}
}
}
}
}
}
@@ -264,45 +292,39 @@ public class BatteryReportActivity extends Activity {
}
}
/**
/**
* 获取应用运行时长(返回包名-时长映射,不处理名称 )
* 获取应用运行时长(逻辑不变, 返回24小时运行时长 )
*/
*/
private Map < String , Long > getAppRunTime ( ) {
private Map < String , Long > getAppRunTime ( ) {
Map < String , Long > runTimeMap = new HashMap < String , Long > ( ) ;
Map < String , Long > runTimeMap = new HashMap < String , Long > ( ) ;
if ( Build . VERSION . SDK_INT > = Build . VERSION_CODES . LOLLIPOP ) {
if ( Build . VERSION . SDK_INT > = Build . VERSION_CODES . LOLLIPOP ) {
try {
try {
android . app . usage . UsageStatsManager manager =
android . app . usage . UsageStatsManager manager =
( android . app . usage . UsageStatsManager ) getSystemService ( Context . USAGE_STATS_SERVICE ) ;
( android . app . usage . UsageStatsManager ) getSystemService ( Context . USAGE_STATS_SERVICE ) ;
long endTime = System . currentTimeMillis ( ) ;
long endTime = System . currentTimeMillis ( ) ;
long startTime = endTime - 24 * 3600 * 1000 ; // 近24小时
long startTime = endTime - 24 * 3600 * 1000 ; // 近24小时
List < android . app . usage . UsageStats > statsList = manager . queryUsageStats (
List < android . app . usage . UsageStats > statsList = manager . queryUsageStats (
android . app . usage . UsageStatsManager . INTERVAL_DAILY , startTime , endTime ) ;
android . app . usage . UsageStatsManager . INTERVAL_DAILY , startTime , endTime ) ;
// 仅存储包名和时长(不查名称)
for ( android . app . usage . UsageStats stats : statsList ) {
for ( android . app . usage . UsageStats stats : statsList ) {
long runTimeMs = stats . getTotalTimeInForeground ( ) ;
long runTimeMs = stats . getTotalTimeInForeground ( ) ;
String packageName = stats . getPackageName ( ) ;
String packageName = stats . getPackageName ( ) ;
LogUtils . d ( TAG , " 包名 " + packageName + " 运行时长: " + formatRunTime ( runTimeMs ) ) ;
LogUtils . d ( TAG , " 包名 " + packageName + " 24小时 运行时长:" + formatRunTime ( runTimeMs ) ) ;
runTimeMap . put ( packageName , runTimeMs ) ;
runTimeMap . put ( packageName , runTimeMs ) ;
if ( packageName . equals ( " aidepro.top " ) ) {
if ( packageName . equals ( " aidepro.top " ) ) {
LogUtils . d ( TAG , String . format ( " runTimeMap.put(packageName, runTimeMs) 特殊查询 %s 查询有结果。 " , packageName ) ) ;
LogUtils . d ( TAG , String . format ( " runTimeMap.put(packageName, runTimeMs) 特殊查询 %s 查询有结果。 " , packageName ) ) ;
}
}
}
}
} catch ( Exception e ) {
} catch ( Exception e ) {
LogUtils . e ( TAG , " 获取应用运行时长失败: " + e . getMessage ( ) ) ;
LogUtils . e ( TAG , " 获取应用运行时长失败: " + e . getMessage ( ) ) ;
}
}
}
}
/*if(runTimeMap.containsKey("aidepro.top"))
LogUtils . d ( TAG , String . format ( " 应用运行时长列表数量%d。 " , runTimeMap . size ( ) ) ) ;
{
LogUtils.d(TAG, "aidepro.top OK");
}*/
LogUtils . d ( TAG , String . format ( " 应用运行时长列表数量%d。 " , runTimeMap . size ( ) ) ) ;
return runTimeMap ;
return runTimeMap ;
}
}
/**
/**
* 格式化运行时长(工具方法,与包名无关 )
* 格式化运行时长(逻辑不变 )
*/
*/
private String formatRunTime ( long runTimeMs ) {
private String formatRunTime ( long runTimeMs ) {
if ( runTimeMs < = 0 ) {
if ( runTimeMs < = 0 ) {
@@ -323,48 +345,7 @@ public class BatteryReportActivity extends Activity {
}
}
/**
/**
* 分配电池消耗(全程用包名计算,不涉及名称 )
* 权限检查(逻辑不变 )
*/
private void distributeBatteryConsumption ( float totalDropPercent , Map < String , Long > runTimeMap ) {
long totalRunTime = 0 ;
// 遍历包名计算总时长
for ( Map . Entry < String , Long > entry : runTimeMap . entrySet ( ) ) {
totalRunTime + = entry . getValue ( ) ;
}
// 按包名匹配计算各应用耗电
for ( AppBatteryModel model : dataList ) {
String packageName = model . getPackageName ( ) ;
Long appRunTime ;
// Java7 显式判断包名是否存在
if ( runTimeMap . containsKey ( packageName ) ) {
appRunTime = runTimeMap . get ( packageName ) ;
} else {
appRunTime = 0L ;
}
float ratio = ( totalRunTime > 0 ) ? ( float ) appRunTime / totalRunTime : 0 ;
float consumption = batteryCapacity * totalDropPercent / 100 * ratio ;
model . setConsumption ( String . format ( " %.1f " , consumption ) ) ;
model . setRunTime ( appRunTime ) ; // 同步更新时长
}
// 按耗电排序(用包名对应的耗电值排序)
Collections . sort ( dataList , new Comparator < AppBatteryModel > ( ) {
@Override
public int compare ( AppBatteryModel m1 , AppBatteryModel m2 ) {
float c1 = Float . parseFloat ( m1 . getConsumption ( ) ) ;
float c2 = Float . parseFloat ( m2 . getConsumption ( ) ) ;
return Float . compare ( c2 , c1 ) ; // 逆序(耗电从高到低)
}
} ) ;
// 重新应用包名过滤
filterAppsByPackage ( etSearch . getText ( ) . toString ( ) ) ;
}
/**
* 权限检查(仅操作系统服务,与包名无关)
*/
*/
private boolean hasUsageStatsPermission ( Context context ) {
private boolean hasUsageStatsPermission ( Context context ) {
if ( Build . VERSION . SDK_INT < Build . VERSION_CODES . LOLLIPOP ) {
if ( Build . VERSION . SDK_INT < Build . VERSION_CODES . LOLLIPOP ) {
@@ -372,7 +353,7 @@ public class BatteryReportActivity extends Activity {
}
}
android . app . usage . UsageStatsManager manager =
android . app . usage . UsageStatsManager manager =
( android . app . usage . UsageStatsManager ) context . getSystemService ( Context . USAGE_STATS_SERVICE ) ;
( android . app . usage . UsageStatsManager ) context . getSystemService ( Context . USAGE_STATS_SERVICE ) ;
if ( manager = = null ) {
if ( manager = = null ) {
return false ;
return false ;
}
}
@@ -380,37 +361,49 @@ public class BatteryReportActivity extends Activity {
long endTime = System . currentTimeMillis ( ) ;
long endTime = System . currentTimeMillis ( ) ;
long startTime = endTime - 1000 * 60 ;
long startTime = endTime - 1000 * 60 ;
List < android . app . usage . UsageStats > statsList = manager . queryUsageStats (
List < android . app . usage . UsageStats > statsList = manager . queryUsageStats (
android . app . usage . UsageStatsManager . INTERVAL_DAILY , startTime , endTime ) ;
android . app . usage . UsageStatsManager . INTERVAL_DAILY , startTime , endTime ) ;
return statsList ! = null & & ! statsList . isEmpty ( ) ;
return statsList ! = null & & ! statsList . isEmpty ( ) ;
}
}
/**
/**
* 数据模型(仅存储包名、耗电、时长,不存名称)
* 【核心修改】数据模型:明确字段含义
* - consumption: 单次耗电( 两次电池广播间的消耗, float类型便于计算)
* - totalConsumption: 累计耗电( 24小时初始化值+后续单次累加,显示用)
*/
*/
public static class AppBatteryModel {
public static class AppBatteryModel {
private String packageName ; // 核心标识: 应用包名
private String packageName ; // 应用包名(核心标识)
private String consumption ; // 电量消耗( mAh )
private float consumption ; // 单次耗电( mAh, float类型 )
private long runTime ; // 运行时长( ms )
private f loat totalConsumption ; // 累计耗电( mAh, 显示+排序用 )
private long runTime ; // 运行时长( ms)
// Java7 显式构造(仅传入包名、初始耗电、初始时长)
// Java7 显式构造: 初始化单次耗电、累计耗电为0
public AppBatteryModel ( String packageName , String c onsumption, long runTime ) {
public AppBatteryModel ( String packageName , float consumption , float totalC onsumption, long runTime ) {
this . packageName = packageName ;
this . packageName = packageName ;
this . consumption = consumption ;
this . consumption = consumption ; // 单次耗电初始为0
this . totalConsumption = totalConsumption ; // 累计耗电初始为0( 后续初始化时赋值)
this . runTime = runTime ;
this . runTime = runTime ;
}
}
// Getter/Setter(仅操作包名、耗电、时长)
// Getter/Setter:覆盖所有字段,确保数据操作正常
public String getPackageName ( ) {
public String getPackageName ( ) {
return packageName ;
return packageName ;
}
}
public String getConsumption ( ) {
public float getConsumption ( ) {
return consumption ;
return consumption ; // 获取单次耗电
}
}
public void setConsumption ( String consumption ) {
public void setConsumption ( float consumption ) {
this . consumption = consumption ;
this . consumption = consumption ; // 设置单次耗电
}
public float getTotalConsumption ( ) {
return totalConsumption ; // 获取累计耗电(显示用)
}
public void setTotalConsumption ( float totalConsumption ) {
this . totalConsumption = totalConsumption ; // 设置累计耗电(初始化/累加用)
}
}
public long getRunTime ( ) {
public long getRunTime ( ) {
@@ -423,34 +416,37 @@ public class BatteryReportActivity extends Activity {
}
}
/**
/**
* RecyclerView 适配器(仅在显示时通过包名查询应用名称)
* RecyclerView 适配器: 仅显示累计耗电( totalConsumption) , 逻辑适配模型修改
*/
*/
public static class BatteryReportAdapter extends RecyclerView . Adapter < BatteryReportAdapter . ViewHolder > {
public static class BatteryReportAdapter extends RecyclerView . Adapter < BatteryReportAdapter . ViewHolder > {
private Context mContext ;
private Context mContext ;
private List < AppBatteryModel > mDataList ;
private List < AppBatteryModel > mDataList ;
private PackageManager mPm ; // 用于显示时查询应用名称
private PackageManager mPm ;
private Map < String , String > mPackageToNameCache ;
// Java7 显式构造(传入包管理工具)
// Java7 显式构造:接收名称缓存,确保显示时高效获取应用名
public BatteryReportAdapter ( Context context , List < AppBatteryModel > dataList , PackageManager pm ) {
public BatteryReportAdapter ( Context context , List < AppBatteryModel > dataList ,
PackageManager pm , Map < String , String > packageToNameCache ) {
this . mContext = context ;
this . mContext = context ;
this . mDataList = dataList ;
this . mDataList = dataList ;
this . mPm = pm ; // 持有包管理工具,供显示时查名称
this . mPm = pm ;
this . mPackageToNameCache = packageToNameCache ;
}
}
@Override
@Override
public ViewHolder onCreateViewHolder ( ViewGroup parent , int viewType ) {
public ViewHolder onCreateViewHolder ( ViewGroup parent , int viewType ) {
// 加载系统列表项布局( text1显示应用名, text2显示累计耗电+时长)
View itemView = LayoutInflater . from ( mContext )
View itemView = LayoutInflater . from ( mContext )
. inflate ( android . R . layout . simple_list_item_2 , parent , false ) ;
. inflate ( android . R . layout . simple_list_item_2 , parent , false ) ;
return new ViewHolder ( itemView ) ;
return new ViewHolder ( itemView ) ;
}
}
// 绑定数据:核心修改——仅在此处通过包名查询应用名称并显示
@Override
@Override
public void onBindViewHolder ( ViewHolder holder , int position ) {
public void onBindViewHolder ( ViewHolder holder , int position ) {
// Java7 显式非空判断( 避免空指针)
// Java7 显式非空判断: 避免空指针异常
if ( mDataList = = null | | mDataList . isEmpty ( ) | | position > = mDataList . size ( ) ) {
if ( mDataList = = null | | mDataList . isEmpty ( ) | | position > = mDataList . size ( ) ) {
holder . tvAppName . setText ( " 未知应用 " ) ;
holder . tvAppName . setText ( " 未知应用 " ) ;
holder . tvConsumption . setText ( " 耗电: 0.0 mAh | 运行时长: 0秒 " ) ;
holder . tvConsumption . setText ( " 累计 耗电: 0.0 mAh | 运行时长: 0秒" ) ;
return ;
return ;
}
}
@@ -458,59 +454,59 @@ public class BatteryReportActivity extends Activity {
String packageName = model . getPackageName ( ) ;
String packageName = model . getPackageName ( ) ;
String appName = " " ;
String appName = " " ;
// 关键步骤:通过包名查询应用名称(仅显示时执行,不影响数据计算)
// 优先从缓存获取应用名: 减少PackageManager调用, 提升性能
try {
if ( mPackageToNameCache ! = null & & mPackageToNameCache . containsKey ( packageName ) ) {
ApplicationInfo appInfo = mPm . getApplicationInfo ( packageName , 0 );
appName = mPackageToNameCache . get ( packageName ) ;
appName = mPm . getApplicationLabel ( appInfo ) . toString ( ) ;
} catch ( PackageManager . NameNotFoundException e ) {
// 包名不存在(如应用已卸载),用包名作为名称兜底
appName = packageName ;
LogUtils . e ( " Adapter " , " 包名 " + packageName + " 对应的应用未找到: " + e . getMessage ( ) ) ;
} catch ( Exception e ) {
// 其他异常(如权限问题),同样用包名兜底
appName = packageName ;
LogUtils . e ( " Adapter " , " 查询应用名称失败(包名: " + packageName + " ) : " + e . getMessage ( ) ) ;
}
// 显示应用名称(查询到则显示名称,否则显示包名)
holder . tvAppName . setText ( appName ) ;
// 格式化运行时长(调用 Activity 的工具方法)
String runTimeStr = ( ( BatteryReportActivity ) mContext ) . formatRunTime ( model . getRunTime ( ) ) ;
// 显示耗电+运行时长(基于包名计算的结果)
String consumptionText = String . format ( " 耗电:%s mAh | 运行时长:%s " ,
model . getConsumption ( ) , runTimeStr ) ;
holder . tvConsumption . setText ( consumptionText ) ;
// 优化显示:目标应用文字标蓝(通过包名匹配)
if ( BatteryReportActivity . TARGET_APP_PACKAGE . equals ( packageName ) ) {
holder . tvAppName . setTextColor ( mContext . getResources ( ) . getColor ( android . R . color . holo_blue_dark ) ) ;
holder . tvConsumption . setTextColor ( mContext . getResources ( ) . getColor ( android . R . color . holo_blue_dark ) ) ;
} else {
} else {
holder . tvAppName . setTextColor ( mContext . getResources ( ) . getColor ( android . R . color . black ) ) ;
// 缓存无数据时兜底查询,并同步更新缓存
holder . tvConsumption . setTextColor ( mContext . getResources ( ) . getColor ( android . R . color . darker_gray ) ) ;
try {
ApplicationInfo appInfo = mPm . getApplicationInfo ( packageName , 0 ) ;
appName = mPm . getApplicationLabel ( appInfo ) . toString ( ) ;
if ( mPackageToNameCache ! = null ) {
mPackageToNameCache . put ( packageName , appName ) ;
}
} catch ( PackageManager . NameNotFoundException e ) {
appName = packageName ; // 包名不存在时用包名兜底
LogUtils . e ( " Adapter " , " 包名 " + packageName + " 对应的应用未找到: " + e . getMessage ( ) ) ;
} catch ( Exception e ) {
appName = packageName ; // 其他异常时用包名兜底
LogUtils . e ( " Adapter " , " 查询应用名称失败(包名: " + packageName + " ) : " + e . getMessage ( ) ) ;
}
}
}
// 调整文字大小(提升可读性)
// 显示逻辑: 仅展示累计耗电( totalConsumption) , 隐藏单次耗电
holder . tvAppName . setText ( appName ) ;
// 格式化运行时长 + 累计耗电( 保留1位小数, 提升可读性)
String runTimeStr = ( ( BatteryReportActivity ) mContext ) . formatRunTime ( model . getRunTime ( ) ) ;
String totalConsumptionText = String . format ( " 累计耗电:%.1f mAh | 运行时长:%s " ,
model . getTotalConsumption ( ) , runTimeStr ) ;
holder . tvConsumption . setText ( totalConsumptionText ) ;
// 显示优化:文字颜色区分(避免所有应用均标蓝,仅示例可按需修改)
holder . tvAppName . setTextColor ( mContext . getResources ( ) . getColor ( android . R . color . black ) ) ;
holder . tvConsumption . setTextColor ( mContext . getResources ( ) . getColor ( android . R . color . darker_gray ) ) ;
// 调整文字大小:适配手机屏幕,提升可读性
holder . tvAppName . setTextSize ( 16 ) ;
holder . tvAppName . setTextSize ( 16 ) ;
holder . tvConsumption . setTextSize ( 14 ) ;
holder . tvConsumption . setTextSize ( 14 ) ;
}
}
// 获取列表长度( Java7 三元运算符)
// 获取列表长度: Java7 三元运算符判断空值,避免空指针
@Override
@Override
public int getItemCount ( ) {
public int getItemCount ( ) {
return mDataList = = null ? 0 : mDataList . size ( ) ;
return mDataList = = null ? 0 : mDataList . size ( ) ;
}
}
// ViewHolder( 绑定系统布局的两个 TextView)
/**
* ViewHolder: 绑定系统布局控件, 与显示逻辑对应
*/
public static class ViewHolder extends RecyclerView . ViewHolder {
public static class ViewHolder extends RecyclerView . ViewHolder {
TextView tvAppName ; // 显示应用名称(通过包名查询)
TextView tvAppName ; // 显示应用名称
TextView tvConsumption ; // 显示耗电+运行时长(包名计算结果)
TextView tvConsumption ; // 显示累计耗电 + 运行时长
// Java7 显式构造
// Java7 显式构造: 绑定控件ID( 系统布局固定ID: text1、text2)
public ViewHolder ( View itemView ) {
public ViewHolder ( View itemView ) {
super ( itemView ) ;
super ( itemView ) ;
// 强制类型转换(系统布局控件 ID: text1 和 text2)
tvAppName = ( TextView ) itemView . findViewById ( android . R . id . text1 ) ;
tvAppName = ( TextView ) itemView . findViewById ( android . R . id . text1 ) ;
tvConsumption = ( TextView ) itemView . findViewById ( android . R . id . text2 ) ;
tvConsumption = ( TextView ) itemView . findViewById ( android . R . id . text2 ) ;
}
}