修复应用电量消耗计算不准确的问题。
This commit is contained in:
		| @@ -1,8 +1,8 @@ | ||||
| #Created by .winboll/winboll_app_build.gradle | ||||
| #Wed Oct 22 18:58:26 HKT 2025 | ||||
| #Wed Oct 22 12:10:38 GMT 2025 | ||||
| stageCount=17 | ||||
| libraryProject= | ||||
| baseVersion=15.4 | ||||
| publishVersion=15.4.16 | ||||
| buildCount=0 | ||||
| buildCount=3 | ||||
| baseBetaVersion=15.4.17 | ||||
|   | ||||
| @@ -39,7 +39,6 @@ public class BatteryReportActivity extends Activity { | ||||
|  | ||||
|     private RecyclerView rvBatteryReport; | ||||
|     private BatteryReportAdapter adapter; | ||||
|     // 数据列表:仅存储包名、耗电、时长(不存储名称,计算全程用包名) | ||||
|     private List<AppBatteryModel> dataList = new ArrayList<AppBatteryModel>();  | ||||
|     private List<AppBatteryModel> filteredList = new ArrayList<AppBatteryModel>();  | ||||
|     private BroadcastReceiver batteryReceiver; | ||||
| @@ -47,18 +46,14 @@ public class BatteryReportActivity extends Activity { | ||||
|     private float lastBatteryPercent = 100.0f; | ||||
|     private long lastCheckTime = System.currentTimeMillis(); | ||||
|     private EditText etSearch; | ||||
|     // 应用运行时长缓存(key:包名,value:时长ms) | ||||
|     private Map<String, Long> appRunTimeCache = new HashMap<String, Long>(); | ||||
|     // 新增:包名-应用名称映射缓存(用于搜索匹配名称,避免重复查询) | ||||
|     private Map<String, String> packageToAppNameCache = new HashMap<String, String>(); | ||||
|     // 包管理工具(全局持有,避免重复获取) | ||||
|     private PackageManager mPackageManager; | ||||
|  | ||||
|     @Override | ||||
|     protected void onCreate(Bundle savedInstanceState) { | ||||
|         super.onCreate(savedInstanceState); | ||||
|         setContentView(R.layout.activity_battery_report); | ||||
|         // 初始化包管理工具(仅一次,供后续查询名称使用) | ||||
|         mPackageManager = getPackageManager(); | ||||
|  | ||||
|         // 权限检查(Java7 传统条件判断) | ||||
| @@ -72,34 +67,31 @@ public class BatteryReportActivity extends Activity { | ||||
|         rvBatteryReport = (RecyclerView) findViewById(R.id.rv_battery_report);  | ||||
|         rvBatteryReport.setLayoutManager(new LinearLayoutManager(this)); | ||||
|  | ||||
|         // 1. 加载所有应用(仅存包名,不查名称) | ||||
|         // 初始化流程:新增“加载24小时累计耗电”步骤 | ||||
|         loadAllAppPackage(); | ||||
|         // 2. 预缓存所有包名对应的应用名称(为搜索名称做准备) | ||||
|         preCacheAllAppNames(); | ||||
|         // 4. 首次获取运行时长(key:包名) | ||||
|         appRunTimeCache = getAppRunTime(); | ||||
|         // 5. 更新时长到数据模型(用包名匹配) | ||||
|         updateAppRunTimeToModel(); | ||||
|         // 6. 初始化过滤列表和适配器(传入包管理工具+名称缓存) | ||||
|         calculateInitial24hTotalConsumption(); // 初始化时计算24小时累计耗电 | ||||
|         filteredList.addAll(dataList); | ||||
|         adapter = new BatteryReportAdapter(this, filteredList, mPackageManager, packageToAppNameCache); | ||||
|         rvBatteryReport.setAdapter(adapter); | ||||
|  | ||||
|         // 搜索监听:修改为“包名+应用名称”双匹配 | ||||
|         // 搜索监听(不变) | ||||
|         etSearch.addTextChangedListener(new TextWatcher() { | ||||
| 				@Override | ||||
| 				public void beforeTextChanged(CharSequence s, int start, int count, int after) {} | ||||
|  | ||||
| 				@Override | ||||
| 				public void onTextChanged(CharSequence s, int start, int before, int count) { | ||||
| 					filterAppsByPackageAndName(s.toString()); // 替换为新的双维度过滤方法 | ||||
| 					filterAppsByPackageAndName(s.toString()); | ||||
| 				} | ||||
|  | ||||
| 				@Override | ||||
| 				public void afterTextChanged(Editable s) {} | ||||
| 			}); | ||||
|  | ||||
|         // 电池广播(耗电计算全程用包名) | ||||
|         // 电池广播:调用修改后的“单次耗电计算+累计累加”方法 | ||||
|         batteryReceiver = new BroadcastReceiver() { | ||||
|             @Override | ||||
|             public void onReceive(Context context, Intent intent) { | ||||
| @@ -108,17 +100,13 @@ public class BatteryReportActivity extends Activity { | ||||
|                 float currentPercent = (float) level / scale * 100; | ||||
|                 LogUtils.d(TAG, "电池百分比变化:" + lastBatteryPercent + " -> " + currentPercent); | ||||
|  | ||||
|                 // 计算电池消耗并更新数据(全程用包名) | ||||
|                 if (currentPercent < lastBatteryPercent) { | ||||
|                     float dropPercent = lastBatteryPercent - currentPercent; | ||||
|                     long duration = System.currentTimeMillis() - lastCheckTime; | ||||
|                     LogUtils.d(TAG, "电池消耗:" + dropPercent + "%,时长:" + duration + "ms"); | ||||
|                     // 重新获取最新运行时长(key:包名) | ||||
|                     appRunTimeCache = getAppRunTime(); | ||||
|                     // 更新模型中的运行时长(包名匹配) | ||||
|                     updateAppRunTimeToModel(); | ||||
|                     // 分配耗电(包名计算) | ||||
|                     distributeBatteryConsumption(dropPercent, appRunTimeCache); | ||||
|                     calculateSingleConsumptionAndAccumulate(dropPercent, appRunTimeCache); // 单次+累计逻辑 | ||||
|                 } | ||||
|  | ||||
|                 lastBatteryPercent = currentPercent; | ||||
| @@ -138,67 +126,63 @@ public class BatteryReportActivity extends Activity { | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 加载所有应用(仅获取包名,不查询应用名称,数据计算核心步骤) | ||||
|      * 加载所有应用(仅获取包名,初始化模型时单次耗电、累计耗电均设为0) | ||||
|      */ | ||||
|     private void loadAllAppPackage() { | ||||
|         List<ApplicationInfo> appList = mPackageManager.getInstalledApplications(PackageManager.GET_META_DATA); | ||||
|         dataList.clear(); // 清空列表避免重复 | ||||
|         dataList.clear(); | ||||
|  | ||||
|         LogUtils.d(TAG, "开始加载应用包名列表,共找到" + appList.size() + "个应用"); | ||||
|  | ||||
|         // 仅遍历包名,不处理名称(避免名称获取异常影响) | ||||
|         for (ApplicationInfo appInfo : appList) { | ||||
|             String packageName = appInfo.packageName; | ||||
|             // 模型仅存包名、初始耗电0、初始时长0(名称显示/搜索时用缓存) | ||||
|             dataList.add(new AppBatteryModel(packageName, "0.0", 0)); | ||||
|             // 初始化:单次耗电(consumption)=0,累计耗电(totalConsumption)=0,运行时长=0 | ||||
|             dataList.add(new AppBatteryModel(packageName, 0.0f, 0.0f, 0)); | ||||
|         } | ||||
|  | ||||
|         LogUtils.d(TAG, "应用包名列表加载完成,共添加" + dataList.size() + "个包名。"); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 新增:预缓存所有包名对应的应用名称(为搜索提供支持,避免重复查询) | ||||
|      * 预缓存应用名称(逻辑不变) | ||||
|      */ | ||||
|     private void preCacheAllAppNames() { | ||||
|         packageToAppNameCache.clear(); // 清空旧缓存 | ||||
|         packageToAppNameCache.clear(); | ||||
|         LogUtils.d(TAG, "开始预缓存包名-应用名称映射"); | ||||
|  | ||||
|         for (AppBatteryModel model : dataList) { | ||||
|             String packageName = model.getPackageName(); | ||||
|             String appName = getAppNameByPackage(packageName); // 复用工具方法获取名称 | ||||
|             packageToAppNameCache.put(packageName, appName); // 缓存映射关系 | ||||
|             String appName = getAppNameByPackage(packageName); | ||||
|             packageToAppNameCache.put(packageName, appName); | ||||
|         } | ||||
|  | ||||
|         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; | ||||
|             // Java7 显式判断包名是否在缓存中 | ||||
|             if (appRunTimeCache.containsKey(packageName)) { | ||||
|                 runTime = appRunTimeCache.get(packageName); | ||||
|                 LogUtils.d(TAG, String.format("应用包 %s 运行时长已更新。", packageName)); | ||||
| @@ -213,30 +197,94 @@ public class BatteryReportActivity extends Activity { | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 新增:双维度过滤(包名+应用名称) | ||||
|      * 搜索关键词同时匹配“包名(不区分大小写)”或“应用名称(不区分大小写)” | ||||
|      * 【新增】初始化时计算24小时累计耗电(赋值给totalConsumption) | ||||
|      * 逻辑:基于24小时运行时长占比,分配当前电池容量的理论24小时消耗 | ||||
|      */ | ||||
|     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(); | ||||
|         if (keyword == null || keyword.isEmpty()) { | ||||
|             filteredList.addAll(dataList); | ||||
|         } else { | ||||
|             String lowerKeyword = keyword.toLowerCase(); // 统一转为小写,实现不区分大小写搜索 | ||||
|             String lowerKeyword = keyword.toLowerCase(); | ||||
|  | ||||
|             for (AppBatteryModel model : dataList) { | ||||
|                 String packageName = model.getPackageName(); | ||||
|                 String packageNameLower = packageName.toLowerCase(); | ||||
|                 // 从缓存中获取应用名称(避免重复查询PackageManager) | ||||
|                 String appName = packageToAppNameCache.get(packageName); | ||||
|                 String appNameLower = appName.toLowerCase(); | ||||
|  | ||||
|                 // 匹配规则:包名包含关键词 OR 应用名称包含关键词 | ||||
|                 boolean isMatched = packageNameLower.contains(lowerKeyword)  | ||||
| 					|| appNameLower.contains(lowerKeyword); | ||||
|                     || appNameLower.contains(lowerKeyword); | ||||
|  | ||||
|                 if (isMatched) { | ||||
|                     filteredList.add(model); | ||||
|  | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| @@ -244,7 +292,7 @@ public class BatteryReportActivity extends Activity { | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 获取应用运行时长(返回包名-时长映射,不处理名称) | ||||
|      * 获取应用运行时长(逻辑不变,返回24小时运行时长) | ||||
|      */ | ||||
|     private Map<String, Long> getAppRunTime() { | ||||
|         Map<String, Long> runTimeMap = new HashMap<String, Long>(); | ||||
| @@ -257,11 +305,10 @@ public class BatteryReportActivity extends Activity { | ||||
|                 List<android.app.usage.UsageStats> statsList = manager.queryUsageStats( | ||||
|                     android.app.usage.UsageStatsManager.INTERVAL_DAILY, startTime, endTime); | ||||
|  | ||||
|                 // 仅存储包名和时长(不查名称) | ||||
|                 for (android.app.usage.UsageStats stats : statsList) { | ||||
|                     long runTimeMs = stats.getTotalTimeInForeground(); | ||||
|                     String packageName = stats.getPackageName(); | ||||
|                     LogUtils.d(TAG, "包名" + packageName + "运行时长:" + formatRunTime(runTimeMs)); | ||||
|                     LogUtils.d(TAG, "包名" + packageName + "24小时运行时长:" + formatRunTime(runTimeMs)); | ||||
|                     runTimeMap.put(packageName, runTimeMs); | ||||
|                     if (packageName.equals("aidepro.top")) { | ||||
|                         LogUtils.d(TAG, String.format("runTimeMap.put(packageName, runTimeMs) 特殊查询 %s 查询有结果。", packageName)); | ||||
| @@ -277,7 +324,7 @@ public class BatteryReportActivity extends Activity { | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 格式化运行时长(工具方法,与包名无关) | ||||
|      * 格式化运行时长(逻辑不变) | ||||
|      */ | ||||
|     private String formatRunTime(long runTimeMs) { | ||||
|         if (runTimeMs <= 0) { | ||||
| @@ -298,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); // 逆序(耗电从高到低) | ||||
| 				} | ||||
| 			}); | ||||
|  | ||||
|         // 重新应用“包名+名称”双维度过滤 | ||||
|         filterAppsByPackageAndName(etSearch.getText().toString()); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 权限检查(仅操作系统服务,与包名无关) | ||||
|      * 权限检查(逻辑不变) | ||||
|      */ | ||||
|     private boolean hasUsageStatsPermission(Context context) { | ||||
|         if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { | ||||
| @@ -361,31 +367,43 @@ public class BatteryReportActivity extends Activity { | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 数据模型(仅存储包名、耗电、时长,不存名称) | ||||
|      * 【核心修改】数据模型:明确字段含义 | ||||
|      * - consumption:单次耗电(两次电池广播间的消耗,float类型便于计算) | ||||
|      * - totalConsumption:累计耗电(24小时初始化值+后续单次累加,显示用) | ||||
|      */ | ||||
|     public static class AppBatteryModel { | ||||
|         private String packageName; // 核心标识:应用包名 | ||||
|         private String consumption; // 电量消耗(mAh) | ||||
|         private long runTime;       // 运行时长(ms) | ||||
|         private String packageName;    // 应用包名(核心标识) | ||||
|         private float consumption;     // 单次耗电(mAh,float类型) | ||||
|         private float totalConsumption;// 累计耗电(mAh,显示+排序用) | ||||
|         private long runTime;          // 运行时长(ms) | ||||
|  | ||||
|         // Java7 显式构造(仅传入包名、初始耗电、初始时长) | ||||
|         public AppBatteryModel(String packageName, String consumption, long runTime) { | ||||
| 		// Java7 显式构造:初始化单次耗电、累计耗电为0 | ||||
|         public AppBatteryModel(String packageName, float consumption, float totalConsumption, long runTime) { | ||||
|             this.packageName = packageName; | ||||
|             this.consumption = consumption; | ||||
|             this.consumption = consumption; // 单次耗电初始为0 | ||||
|             this.totalConsumption = totalConsumption; // 累计耗电初始为0(后续初始化时赋值) | ||||
|             this.runTime = runTime; | ||||
|         } | ||||
|  | ||||
|         // Getter/Setter(仅操作包名、耗电、时长) | ||||
|         // Getter/Setter:覆盖所有字段,确保数据操作正常 | ||||
|         public String getPackageName() { | ||||
|             return packageName; | ||||
|         } | ||||
|  | ||||
|         public String getConsumption() { | ||||
|             return consumption; | ||||
|         public float getConsumption() { | ||||
|             return consumption; // 获取单次耗电 | ||||
|         } | ||||
|  | ||||
|         public void setConsumption(String consumption) { | ||||
|             this.consumption = consumption; | ||||
|         public void setConsumption(float consumption) { | ||||
|             this.consumption = consumption; // 设置单次耗电 | ||||
|         } | ||||
|  | ||||
|         public float getTotalConsumption() { | ||||
|             return totalConsumption; // 获取累计耗电(显示用) | ||||
|         } | ||||
|  | ||||
|         public void setTotalConsumption(float totalConsumption) { | ||||
|             this.totalConsumption = totalConsumption; // 设置累计耗电(初始化/累加用) | ||||
|         } | ||||
|  | ||||
|         public long getRunTime() { | ||||
| @@ -398,37 +416,37 @@ public class BatteryReportActivity extends Activity { | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * RecyclerView 适配器(支持从缓存获取名称,避免重复查询) | ||||
|      * RecyclerView 适配器:仅显示累计耗电(totalConsumption),逻辑适配模型修改 | ||||
|      */ | ||||
|     public static class BatteryReportAdapter extends RecyclerView.Adapter<BatteryReportAdapter.ViewHolder> { | ||||
|         private Context mContext; | ||||
|         private List<AppBatteryModel> mDataList; | ||||
|         private PackageManager mPm; // 兜底用:缓存无名称时查询 | ||||
|         private Map<String, String> mPackageToNameCache; // 新增:名称缓存映射 | ||||
|         private PackageManager mPm; | ||||
|         private Map<String, String> mPackageToNameCache; | ||||
|  | ||||
|         // Java7 显式构造(新增名称缓存参数) | ||||
|         // Java7 显式构造:接收名称缓存,确保显示时高效获取应用名 | ||||
|         public BatteryReportAdapter(Context context, List<AppBatteryModel> dataList,  | ||||
|                                     PackageManager pm, Map<String, String> packageToNameCache) { | ||||
|             this.mContext = context; | ||||
|             this.mDataList = dataList; | ||||
|             this.mPm = pm; | ||||
|             this.mPackageToNameCache = packageToNameCache; // 接收名称缓存 | ||||
|             this.mPackageToNameCache = packageToNameCache; | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { | ||||
|             // 加载系统列表项布局(text1显示应用名,text2显示累计耗电+时长) | ||||
|             View itemView = LayoutInflater.from(mContext) | ||||
|                 .inflate(android.R.layout.simple_list_item_2, parent, false); | ||||
|             return new ViewHolder(itemView); | ||||
|         } | ||||
|  | ||||
|         // 绑定数据:优先从缓存取名称,无缓存时兜底查询 | ||||
|         @Override | ||||
|         public void onBindViewHolder(ViewHolder holder, int position) { | ||||
|             // Java7 显式非空判断(避免空指针) | ||||
|             // Java7 显式非空判断:避免空指针异常 | ||||
|             if (mDataList == null || mDataList.isEmpty() || position >= mDataList.size()) { | ||||
|                 holder.tvAppName.setText("未知应用"); | ||||
|                 holder.tvConsumption.setText("耗电:0.0 mAh | 运行时长:0秒"); | ||||
|                 holder.tvConsumption.setText("累计耗电:0.0 mAh | 运行时长:0秒"); | ||||
|                 return; | ||||
|             } | ||||
|  | ||||
| @@ -436,66 +454,59 @@ public class BatteryReportActivity extends Activity { | ||||
|             String packageName = model.getPackageName(); | ||||
|             String appName = ""; | ||||
|  | ||||
|             // 优先从缓存获取名称(避免重复调用PackageManager,提升性能) | ||||
|             // 优先从缓存获取应用名:减少PackageManager调用,提升性能 | ||||
|             if (mPackageToNameCache != null && mPackageToNameCache.containsKey(packageName)) { | ||||
|                 appName = mPackageToNameCache.get(packageName); | ||||
|             } else { | ||||
|                 // 缓存无数据时,兜底查询名称(兼容异常场景) | ||||
|                 // 缓存无数据时兜底查询,并同步更新缓存 | ||||
|                 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; | ||||
|                     appName = packageName; // 包名不存在时用包名兜底 | ||||
|                     LogUtils.e("Adapter", "包名" + packageName + "对应的应用未找到:" + e.getMessage()); | ||||
|                 } catch (Exception e) { | ||||
|                     appName = packageName; | ||||
|                     appName = packageName; // 其他异常时用包名兜底 | ||||
|                     LogUtils.e("Adapter", "查询应用名称失败(包名:" + packageName + "):" + e.getMessage()); | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             // 显示应用名称(缓存/兜底结果) | ||||
|             // 显示逻辑:仅展示累计耗电(totalConsumption),隐藏单次耗电 | ||||
|             holder.tvAppName.setText(appName); | ||||
|  | ||||
|             // 格式化运行时长(调用 Activity 的工具方法) | ||||
|             // 格式化运行时长 + 累计耗电(保留1位小数,提升可读性) | ||||
|             String runTimeStr = ((BatteryReportActivity) mContext).formatRunTime(model.getRunTime()); | ||||
|             // 显示耗电+运行时长(基于包名计算的结果) | ||||
|             String consumptionText = String.format("耗电:%s mAh | 运行时长:%s", | ||||
|                                                    model.getConsumption(), runTimeStr); | ||||
|             holder.tvConsumption.setText(consumptionText); | ||||
|             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.setTextColor(mContext.getResources().getColor(android.R.color.holo_blue_dark)); | ||||
| 			holder.tvConsumption.setTextColor(mContext.getResources().getColor(android.R.color.holo_blue_dark)); | ||||
|  | ||||
| 			//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.tvConsumption.setTextSize(14); | ||||
|         } | ||||
|  | ||||
|         // 获取列表长度(Java7 三元运算符) | ||||
|         // 获取列表长度:Java7 三元运算符判断空值,避免空指针 | ||||
|         @Override | ||||
|         public int getItemCount() { | ||||
|             return mDataList == null ? 0 : mDataList.size(); | ||||
|         } | ||||
|  | ||||
|         // ViewHolder(绑定系统布局的两个 TextView) | ||||
|         /** | ||||
|          * ViewHolder:绑定系统布局控件,与显示逻辑对应 | ||||
|          */ | ||||
|         public static class ViewHolder extends RecyclerView.ViewHolder { | ||||
|             TextView tvAppName;     // 显示应用名称(缓存/兜底获取) | ||||
|             TextView tvConsumption; // 显示耗电+运行时长(包名计算结果) | ||||
|             TextView tvAppName;     // 显示应用名称 | ||||
|             TextView tvConsumption; // 显示累计耗电 + 运行时长 | ||||
|  | ||||
|             // Java7 显式构造 | ||||
|             // Java7 显式构造:绑定控件ID(系统布局固定ID:text1、text2) | ||||
|             public ViewHolder(View itemView) { | ||||
|                 super(itemView); | ||||
|                 // 强制类型转换(系统布局控件 ID:text1 和 text2) | ||||
|                 tvAppName = (TextView) itemView.findViewById(android.R.id.text1); | ||||
|                 tvConsumption = (TextView) itemView.findViewById(android.R.id.text2); | ||||
|             } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 ZhanGSKen
					ZhanGSKen