尝试解决二次启动时文件读取问题
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import 'dart:io';
|
||||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
import 'dart:developer' as dev;
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
@@ -8,6 +8,7 @@ import 'package:sqflite/sqflite.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
import 'package:device_info_plus/device_info_plus.dart';
|
||||
//import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
import '../models/device_matching.dart';
|
||||
import '../utils/charge_utils.dart';
|
||||
@@ -84,8 +85,10 @@ class _BatteryHealthPageState extends State<BatteryHealthPage>
|
||||
}
|
||||
|
||||
Future<Database> _initDatabase() async {
|
||||
dev.log('🔵 _initDatabase 开始', name: 'BatteryHealth');
|
||||
Directory appDocDir = await getApplicationDocumentsDirectory();
|
||||
String dbPath = path.join(appDocDir.path, 'battery_health.db');
|
||||
dev.log('🔵 数据库路径: $dbPath', name: 'BatteryHealth');
|
||||
return await openDatabase(
|
||||
dbPath,
|
||||
version: 2,
|
||||
@@ -136,15 +139,18 @@ class _BatteryHealthPageState extends State<BatteryHealthPage>
|
||||
|
||||
// ---------- 设备信息 ----------
|
||||
Future<void> _getDeviceInfo() async {
|
||||
dev.log('🔵 _getDeviceInfo 开始', name: 'BatteryHealth');
|
||||
DeviceInfoPlugin deviceInfo = DeviceInfoPlugin();
|
||||
try {
|
||||
AndroidDeviceInfo androidInfo = await deviceInfo.androidInfo;
|
||||
String model = androidInfo.model;
|
||||
dev.log('🔵 设备型号: $model', name: 'BatteryHealth');
|
||||
setState(() {
|
||||
_deviceModel = DeviceMatching.getModelName(model);
|
||||
_designCap = DeviceMatching.getDesignCapacity(model);
|
||||
});
|
||||
} catch (e) {
|
||||
dev.log('🔵 获取设备信息失败: $e', name: 'BatteryHealth');
|
||||
setState(() {
|
||||
_deviceModel = '魅族21 Pro (默认)';
|
||||
_designCap = 5050;
|
||||
@@ -152,23 +158,25 @@ class _BatteryHealthPageState extends State<BatteryHealthPage>
|
||||
}
|
||||
}
|
||||
|
||||
// ---------- 扫描目录 (SAF 模式) ----------
|
||||
// ---------- 扫描目录 (SAF) ----------
|
||||
Future<void> _scanAndUpdateDB() async {
|
||||
// 检查 SAF 授权状态
|
||||
dev.log('🔵 _scanAndUpdateDB 开始', name: 'BatteryHealth');
|
||||
_safState = await _safService.getPermissionState();
|
||||
if (_safState != SafPermissionState.authorized) {
|
||||
_showSafAuthorizationDialog();
|
||||
dev.log('🔵 _scanAndUpdateDB: 未授权', name: 'BatteryHealth');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
final files = await _safService.listFiles();
|
||||
dev.log('🔵 扫描文件列表: $files', name: 'BatteryHealth');
|
||||
RegExp filePattern = RegExp(r'mbattery_charger_log_(\d{4}_\d{2}_\d{2})$');
|
||||
|
||||
for (String fileName in files) {
|
||||
Match? match = filePattern.firstMatch(fileName);
|
||||
if (match != null) {
|
||||
String dateStr = match.group(1)!.replaceAll('_', '-');
|
||||
dev.log('🔵 处理文件: $fileName, 日期: $dateStr', name: 'BatteryHealth');
|
||||
try {
|
||||
List<String> lines = await _safService.readLogFile(fileName);
|
||||
if (lines.isEmpty) continue;
|
||||
@@ -197,11 +205,14 @@ class _BatteryHealthPageState extends State<BatteryHealthPage>
|
||||
if (maxVolt == null || minVolt == null) continue;
|
||||
|
||||
await _insertOrUpdate(dateStr, cap, maxVolt, minVolt);
|
||||
} catch (_) {}
|
||||
dev.log('🔵 插入数据库: $dateStr, cap=$cap', name: 'BatteryHealth');
|
||||
} catch (e) {
|
||||
dev.log('🔵 处理文件 $fileName 异常: $e', name: 'BatteryHealth');
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
dev.log('[_scanAndUpdateDB] ❌ 扫描异常: $e', name: 'BatteryHealth');
|
||||
dev.log('🔵 _scanAndUpdateDB 异常: $e', name: 'BatteryHealth');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -211,7 +222,9 @@ class _BatteryHealthPageState extends State<BatteryHealthPage>
|
||||
String year = nowUtc.year.toString();
|
||||
String month = nowUtc.month.toString().padLeft(2, '0');
|
||||
String day = nowUtc.day.toString().padLeft(2, '0');
|
||||
return 'mbattery_charger_log_${year}_${month}_$day';
|
||||
String fileName = 'mbattery_charger_log_${year}_${month}_$day';
|
||||
dev.log('🔵 getTodayFileName: $fileName', name: 'BatteryHealth');
|
||||
return fileName;
|
||||
}
|
||||
|
||||
// ---------- 时间戳工具方法 ----------
|
||||
@@ -250,9 +263,10 @@ class _BatteryHealthPageState extends State<BatteryHealthPage>
|
||||
|
||||
// ---------- SAF 授权引导 ----------
|
||||
void _showSafAuthorizationDialog() {
|
||||
dev.log('🔵 _showSafAuthorizationDialog 被调用', name: 'BatteryHealth');
|
||||
if (!mounted) return;
|
||||
|
||||
showDialog(
|
||||
showDialog<String>(
|
||||
context: context,
|
||||
barrierDismissible: false,
|
||||
builder: (context) => AlertDialog(
|
||||
@@ -274,7 +288,8 @@ class _BatteryHealthPageState extends State<BatteryHealthPage>
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
dev.log('🔵 用户取消授权', name: 'BatteryHealth');
|
||||
Navigator.pop(context, 'cancel');
|
||||
setState(() {
|
||||
_safState = SafPermissionState.denied;
|
||||
});
|
||||
@@ -282,48 +297,44 @@ class _BatteryHealthPageState extends State<BatteryHealthPage>
|
||||
child: const Text('取消'),
|
||||
),
|
||||
ElevatedButton(
|
||||
onPressed: () async {
|
||||
// 保存 context 引用
|
||||
final ctx = context;
|
||||
|
||||
// 尝试关闭对话框
|
||||
Navigator.of(ctx, rootNavigator: true).pop();
|
||||
|
||||
// 等待动画完成
|
||||
await Future.delayed(const Duration(milliseconds: 200));
|
||||
|
||||
final result = await _safService.requestPermission();
|
||||
|
||||
if (!mounted) return;
|
||||
|
||||
if (result.success) {
|
||||
setState(() {
|
||||
_safState = SafPermissionState.authorized;
|
||||
});
|
||||
|
||||
// 🟢 兜底:在下一帧再次尝试关闭
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
if (mounted) {
|
||||
Navigator.of(ctx, rootNavigator: true).pop();
|
||||
}
|
||||
});
|
||||
|
||||
readBatteryCapacity();
|
||||
} else {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text(result.errorMessage ?? '授权失败,请重试'),
|
||||
backgroundColor: Colors.red,
|
||||
),
|
||||
);
|
||||
_showSafAuthorizationDialog();
|
||||
}
|
||||
onPressed: () {
|
||||
dev.log('🔵 用户点击选择文件夹', name: 'BatteryHealth');
|
||||
Navigator.pop(context, 'select');
|
||||
},
|
||||
child: const Text('选择文件夹'),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
).then((result) async {
|
||||
dev.log('🔵 对话框关闭,result: $result', name: 'BatteryHealth');
|
||||
if (result == 'select') {
|
||||
dev.log('🔵 开始请求授权', name: 'BatteryHealth');
|
||||
final authResult = await _safService.requestPermission();
|
||||
dev.log(
|
||||
'🔵 授权结果: success=${authResult.success}, state=${authResult.state}',
|
||||
name: 'BatteryHealth',
|
||||
);
|
||||
|
||||
if (!mounted) return;
|
||||
|
||||
if (authResult.success) {
|
||||
dev.log('🔵 授权成功,调用 readBatteryCapacity', name: 'BatteryHealth');
|
||||
setState(() {
|
||||
_safState = SafPermissionState.authorized;
|
||||
});
|
||||
readBatteryCapacity();
|
||||
} else {
|
||||
dev.log('🔵 授权失败: ${authResult.errorMessage}', name: 'BatteryHealth');
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text(authResult.errorMessage ?? '授权失败,请重试'),
|
||||
backgroundColor: Colors.red,
|
||||
),
|
||||
);
|
||||
_showSafAuthorizationDialog();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// ---------- 核心:系统API定调 ----------
|
||||
@@ -531,10 +542,9 @@ class _BatteryHealthPageState extends State<BatteryHealthPage>
|
||||
}
|
||||
}
|
||||
|
||||
// 检查 SAF 授权
|
||||
_safState = await _safService.getPermissionState();
|
||||
if (_safState != SafPermissionState.authorized) {
|
||||
if (mounted) _showSafAuthorizationDialog();
|
||||
dev.log('[_fetchChargeDataFromLog] 未授权,跳过', name: 'BatteryHealth');
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -620,9 +630,17 @@ class _BatteryHealthPageState extends State<BatteryHealthPage>
|
||||
|
||||
// ---------- 读取当前数据 ----------
|
||||
Future<void> readBatteryCapacity() async {
|
||||
dev.log(
|
||||
'🔵 ========== readBatteryCapacity 开始 ==========',
|
||||
name: 'BatteryHealth',
|
||||
);
|
||||
|
||||
// 检查 SAF 授权
|
||||
_safState = await _safService.getPermissionState();
|
||||
dev.log('🔵 SAF状态: $_safState', name: 'BatteryHealth');
|
||||
|
||||
if (_safState != SafPermissionState.authorized) {
|
||||
dev.log('🔵 未授权,弹窗', name: 'BatteryHealth');
|
||||
if (mounted) _showSafAuthorizationDialog();
|
||||
return;
|
||||
}
|
||||
@@ -631,11 +649,16 @@ class _BatteryHealthPageState extends State<BatteryHealthPage>
|
||||
await _scanAndUpdateDB();
|
||||
|
||||
final fileName = getTodayFileName();
|
||||
dev.log('🔵 今日文件名: $fileName', name: 'BatteryHealth');
|
||||
|
||||
final exists = await _safService.logFileExists(fileName);
|
||||
dev.log('🔵 文件存在: $exists', name: 'BatteryHealth');
|
||||
|
||||
if (!exists) {
|
||||
dev.log('🔵 文件不存在,尝试从数据库读取', name: 'BatteryHealth');
|
||||
List<Map<String, dynamic>> recent = await _queryRecentData(1);
|
||||
if (recent.isNotEmpty) {
|
||||
dev.log('🔵 数据库有数据: ${recent.first}', name: 'BatteryHealth');
|
||||
setState(() {
|
||||
_currentCap = recent.first['capacity'].toDouble();
|
||||
_maxVolt = recent.first['volt_max'] ?? 0;
|
||||
@@ -644,6 +667,7 @@ class _BatteryHealthPageState extends State<BatteryHealthPage>
|
||||
});
|
||||
await _updateTrendChart();
|
||||
} else {
|
||||
dev.log('🔵 数据库无数据', name: 'BatteryHealth');
|
||||
setState(() => _hasData = false);
|
||||
}
|
||||
if (_isCharging) _fetchChargeDataFromLog();
|
||||
@@ -654,7 +678,9 @@ class _BatteryHealthPageState extends State<BatteryHealthPage>
|
||||
|
||||
try {
|
||||
final lines = await _safService.readLogFile(fileName);
|
||||
dev.log('🔵 读取到 ${lines.length} 行', name: 'BatteryHealth');
|
||||
if (lines.isEmpty) {
|
||||
dev.log('🔵 文件为空', name: 'BatteryHealth');
|
||||
setState(() => _hasData = false);
|
||||
if (_isCharging) _fetchChargeDataFromLog();
|
||||
_chargeAnimationController.reset();
|
||||
@@ -662,12 +688,23 @@ class _BatteryHealthPageState extends State<BatteryHealthPage>
|
||||
return;
|
||||
}
|
||||
|
||||
// 打印前几行
|
||||
if (lines.isNotEmpty) {
|
||||
dev.log('🔵 第一行: ${lines.first}', name: 'BatteryHealth');
|
||||
if (lines.length > 1) {
|
||||
dev.log('🔵 第二行: ${lines[1]}', name: 'BatteryHealth');
|
||||
}
|
||||
}
|
||||
|
||||
if (_isCharging) _parseChargeDataFromLog(lines);
|
||||
|
||||
List<String> validLines = lines
|
||||
.where((line) => line.contains('tbat='))
|
||||
.toList();
|
||||
dev.log('🔵 有效行数 (含tbat): ${validLines.length}', name: 'BatteryHealth');
|
||||
|
||||
if (validLines.isEmpty) {
|
||||
dev.log('🔵 无有效数据行', name: 'BatteryHealth');
|
||||
setState(() => _hasData = false);
|
||||
_chargeAnimationController.reset();
|
||||
_updateChargeState();
|
||||
@@ -675,6 +712,8 @@ class _BatteryHealthPageState extends State<BatteryHealthPage>
|
||||
}
|
||||
|
||||
String lastLine = validLines.last;
|
||||
dev.log('🔵 最后一行: $lastLine', name: 'BatteryHealth');
|
||||
|
||||
RegExp capReg = RegExp(r'learned_cap=(\d+)');
|
||||
RegExp cycleReg = RegExp(r'cycle=(\d+)');
|
||||
RegExp tempReg = RegExp(r'tbat=(\d+)');
|
||||
@@ -685,7 +724,13 @@ class _BatteryHealthPageState extends State<BatteryHealthPage>
|
||||
String? tempStr = tempReg.firstMatch(lastLine)?.group(1);
|
||||
String? voltStr = voltageReg.firstMatch(lastLine)?.group(1);
|
||||
|
||||
dev.log(
|
||||
'🔵 capStr=$capStr, cycleStr=$cycleStr, tempStr=$tempStr, voltStr=$voltStr',
|
||||
name: 'BatteryHealth',
|
||||
);
|
||||
|
||||
if (capStr == null) {
|
||||
dev.log('🔵 未找到 learned_cap', name: 'BatteryHealth');
|
||||
setState(() => _hasData = false);
|
||||
_chargeAnimationController.reset();
|
||||
_updateChargeState();
|
||||
@@ -697,6 +742,11 @@ class _BatteryHealthPageState extends State<BatteryHealthPage>
|
||||
double temp = double.parse(tempStr ?? '0');
|
||||
double volt = double.parse(voltStr ?? '0') / 1000000;
|
||||
|
||||
dev.log(
|
||||
'🔵 解析结果: capMah=$capMah, cycle=$cycle, temp=$temp, volt=$volt',
|
||||
name: 'BatteryHealth',
|
||||
);
|
||||
|
||||
List<double> temps = [];
|
||||
for (String line in validLines) {
|
||||
RegExpMatch? match = tempReg.firstMatch(line);
|
||||
@@ -731,10 +781,20 @@ class _BatteryHealthPageState extends State<BatteryHealthPage>
|
||||
_hasData = true;
|
||||
});
|
||||
|
||||
dev.log(
|
||||
'🔵 数据更新完成: _currentCap=$_currentCap, _cycleCount=$_cycleCount',
|
||||
name: 'BatteryHealth',
|
||||
);
|
||||
|
||||
await _updateTrendChart();
|
||||
_chargeAnimationController.reset();
|
||||
_updateChargeState();
|
||||
dev.log(
|
||||
'🔵 ========== readBatteryCapacity 完成 ==========',
|
||||
name: 'BatteryHealth',
|
||||
);
|
||||
} catch (e) {
|
||||
dev.log('🔵 readBatteryCapacity 异常: $e', name: 'BatteryHealth');
|
||||
setState(() => _hasData = false);
|
||||
_chargeAnimationController.reset();
|
||||
_updateChargeState();
|
||||
@@ -752,6 +812,7 @@ class _BatteryHealthPageState extends State<BatteryHealthPage>
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
dev.log('🔵 ========== initState 开始 ==========', name: 'BatteryHealth');
|
||||
|
||||
_chargeAnimationController = AnimationController(
|
||||
vsync: this,
|
||||
@@ -786,18 +847,29 @@ class _BatteryHealthPageState extends State<BatteryHealthPage>
|
||||
}
|
||||
});
|
||||
|
||||
// 延迟初始化 SAF 并读取数据
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) async {
|
||||
dev.log('🔵 initState -> addPostFrameCallback 开始', name: 'BatteryHealth');
|
||||
|
||||
await _safService.init();
|
||||
dev.log(
|
||||
'🔵 _safService.init() 完成,cachedUri: ${_safService.cachedUri}',
|
||||
name: 'BatteryHealth',
|
||||
);
|
||||
|
||||
_safState = await _safService.getPermissionState();
|
||||
dev.log('🔵 _safState: $_safState', name: 'BatteryHealth');
|
||||
|
||||
if (_safState == SafPermissionState.unauthorized ||
|
||||
_safState == SafPermissionState.expired) {
|
||||
dev.log('🔵 需要授权,弹窗', name: 'BatteryHealth');
|
||||
if (mounted) _showSafAuthorizationDialog();
|
||||
} else {
|
||||
dev.log('🔵 已有授权,调用 readBatteryCapacity', name: 'BatteryHealth');
|
||||
readBatteryCapacity();
|
||||
}
|
||||
});
|
||||
|
||||
dev.log('🔵 ========== initState 结束 ==========', name: 'BatteryHealth');
|
||||
}
|
||||
|
||||
@override
|
||||
|
||||
Reference in New Issue
Block a user