250 lines
9.0 KiB
C#
250 lines
9.0 KiB
C#
|
|
using System.Collections;
|
|||
|
|
using System.Collections.Generic;
|
|||
|
|
using Unity.VisualScripting;
|
|||
|
|
using UnityEngine;
|
|||
|
|
using UnityEngine.SceneManagement;
|
|||
|
|
|
|||
|
|
public class DCXManager : MonoBehaviour
|
|||
|
|
{
|
|||
|
|
private SerialCommunicationService _serialService;
|
|||
|
|
// public DataService _dataService;
|
|||
|
|
private UserLogService _userLogService;
|
|||
|
|
|
|||
|
|
// 内存监控相关
|
|||
|
|
private float _lastMemoryCheckTime = 0f;
|
|||
|
|
private const float MEMORY_CHECK_INTERVAL = 60f; // 每分钟检查一次内存
|
|||
|
|
|
|||
|
|
// 网络错误日志限流相关
|
|||
|
|
private float _lastNetworkErrorLogTime = 0f;
|
|||
|
|
private const float NETWORK_ERROR_LOG_INTERVAL = 60f; // 每60秒记录一次网络错误
|
|||
|
|
private int _networkErrorCount = 0;
|
|||
|
|
|
|||
|
|
void Awake()
|
|||
|
|
{
|
|||
|
|
DontDestroyOnLoad(gameObject);
|
|||
|
|
#if UNITY_ANDROID && !UNITY_EDITOR
|
|||
|
|
// 设置服务在Awake阶段加载,文件日志也要先启动,才能记录启动恢复来源。
|
|||
|
|
InitializeAndroidLogger();
|
|||
|
|
#endif
|
|||
|
|
BootstrapServices();
|
|||
|
|
|
|||
|
|
// 注册Unity日志回调以捕获网络错误
|
|||
|
|
Application.logMessageReceived += HandleUnityLogs;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void Start()
|
|||
|
|
{
|
|||
|
|
UIManager.Instance.ShowPanel<StandByPanel>();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void Update()
|
|||
|
|
{
|
|||
|
|
// 确保串口服务在主线程中处理接收队列
|
|||
|
|
_serialService?.Update();
|
|||
|
|
|
|||
|
|
// 定期内存检查
|
|||
|
|
CheckMemoryUsage();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 定期检查内存使用情况
|
|||
|
|
/// </summary>
|
|||
|
|
private void CheckMemoryUsage()
|
|||
|
|
{
|
|||
|
|
if (Time.time - _lastMemoryCheckTime >= MEMORY_CHECK_INTERVAL)
|
|||
|
|
{
|
|||
|
|
var memoryUsage = System.GC.GetTotalMemory(false) / (1024 * 1024f); // MB
|
|||
|
|
|
|||
|
|
#if UNITY_ANDROID && !UNITY_EDITOR
|
|||
|
|
// 记录内存使用到文件日志
|
|||
|
|
AndroidFileLogger.Instance?.LogMemoryUsage(memoryUsage,
|
|||
|
|
$"队列状态: {_serialService?.GetQueueStatus() ?? "未知"}");
|
|||
|
|
|
|||
|
|
// 安卓板上内存使用过多时强制清理
|
|||
|
|
if (memoryUsage > 300) // 超过300MB时强制清理
|
|||
|
|
{
|
|||
|
|
AndroidFileLogger.Instance?.LogError("Memory",
|
|||
|
|
$"内存过高({memoryUsage:F1}MB),开始强制清理");
|
|||
|
|
|
|||
|
|
Debug.LogWarning($"[内存警告] 当前内存使用: {memoryUsage:F1}MB,开始强制清理");
|
|||
|
|
|
|||
|
|
// 清理串口队列
|
|||
|
|
_serialService?.ForceCleanQueues();
|
|||
|
|
|
|||
|
|
// 强制垃圾回收
|
|||
|
|
System.GC.Collect();
|
|||
|
|
System.GC.WaitForPendingFinalizers();
|
|||
|
|
System.GC.Collect(); // 二次回收
|
|||
|
|
|
|||
|
|
var memoryAfter = System.GC.GetTotalMemory(false) / (1024 * 1024f);
|
|||
|
|
|
|||
|
|
AndroidFileLogger.Instance?.LogInfo("Memory",
|
|||
|
|
$"清理完成: {memoryUsage:F1}MB -> {memoryAfter:F1}MB, 释放: {(memoryUsage - memoryAfter):F1}MB");
|
|||
|
|
|
|||
|
|
Debug.Log($"[内存清理] 清理后内存: {memoryAfter:F1}MB,释放: {(memoryUsage - memoryAfter):F1}MB");
|
|||
|
|
}
|
|||
|
|
else if (memoryUsage > 200) // 超过200MB时记录警告
|
|||
|
|
{
|
|||
|
|
AndroidFileLogger.Instance?.LogInfo("Memory",
|
|||
|
|
$"内存使用较高: {memoryUsage:F1}MB");
|
|||
|
|
|
|||
|
|
Debug.LogWarning($"[内存监控] 内存使用较高: {memoryUsage:F1}MB");
|
|||
|
|
|
|||
|
|
// 每30秒强制执行一次内存清理
|
|||
|
|
if (Time.time % 30f < 1f)
|
|||
|
|
{
|
|||
|
|
_serialService?.MonitorMemoryUsage();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
#else
|
|||
|
|
// PC上只记录内存使用情况
|
|||
|
|
if (memoryUsage > 500)
|
|||
|
|
{
|
|||
|
|
Debug.LogWarning($"[内存监控] 当前内存使用: {memoryUsage:F1}MB");
|
|||
|
|
}
|
|||
|
|
#endif
|
|||
|
|
|
|||
|
|
_lastMemoryCheckTime = Time.time;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
#if UNITY_ANDROID && !UNITY_EDITOR
|
|||
|
|
/// <summary>
|
|||
|
|
/// 初始化安卓文件日志系统
|
|||
|
|
/// </summary>
|
|||
|
|
private void InitializeAndroidLogger()
|
|||
|
|
{
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
// AndroidFileLogger会自动创建单例并初始化
|
|||
|
|
var logger = AndroidFileLogger.Instance;
|
|||
|
|
if (logger != null)
|
|||
|
|
{
|
|||
|
|
logger.LogInfo("DCXManager", "安卓文件日志系统已初始化");
|
|||
|
|
logger.LogInfo("DCXManager", $"应用启动时间: {System.DateTime.Now:yyyy-MM-dd HH:mm:ss}");
|
|||
|
|
|
|||
|
|
// 记录初始内存状态
|
|||
|
|
var initialMemory = System.GC.GetTotalMemory(false) / (1024 * 1024f);
|
|||
|
|
logger.LogMemoryUsage(initialMemory, "应用启动");
|
|||
|
|
|
|||
|
|
Debug.Log($"[DCXManager] 安卓文件日志系统已启动,日志路径: {logger.GetCurrentLogFilePath()}");
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
Debug.LogError("[DCXManager] 安卓文件日志系统初始化失败");
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
catch (System.Exception ex)
|
|||
|
|
{
|
|||
|
|
Debug.LogError($"[DCXManager] 初始化安卓文件日志系统异常: {ex.Message}");
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
#endif
|
|||
|
|
|
|||
|
|
|
|||
|
|
private void BootstrapServices()
|
|||
|
|
{
|
|||
|
|
// 首先注册数据持久化服务
|
|||
|
|
if (!ServiceLocator.IsRegistered<IDataPersistenceService>())
|
|||
|
|
{
|
|||
|
|
ServiceLocator.Register<IDataPersistenceService>(new DataPersistenceService());
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (!ServiceLocator.IsRegistered<IAuthenticationService>())
|
|||
|
|
{
|
|||
|
|
// 使用新的持久化认证服务替代内存版本
|
|||
|
|
ServiceLocator.Register<IAuthenticationService>(new PersistentAuthenticationService());
|
|||
|
|
}
|
|||
|
|
if(!ServiceLocator.IsRegistered<UserLogService>())
|
|||
|
|
{
|
|||
|
|
_userLogService = new UserLogService();
|
|||
|
|
ServiceLocator.Register<UserLogService>(_userLogService);
|
|||
|
|
}
|
|||
|
|
// 注册串口通信服务
|
|||
|
|
if (!ServiceLocator.IsRegistered<ISerialCommunicationService>())
|
|||
|
|
{
|
|||
|
|
_serialService = new SerialCommunicationService();
|
|||
|
|
ServiceLocator.Register<ISerialCommunicationService>(_serialService);
|
|||
|
|
}
|
|||
|
|
if (!ServiceLocator.IsRegistered<ISystemSettingsService>())
|
|||
|
|
{
|
|||
|
|
ServiceLocator.Register<ISystemSettingsService>(new SystemSettingsService());
|
|||
|
|
}
|
|||
|
|
// if (!ServiceLocator.IsRegistered<IPowerService>())
|
|||
|
|
// {
|
|||
|
|
// ServiceLocator.Register<IPowerService>(new PowerService());
|
|||
|
|
// }
|
|||
|
|
if (!ServiceLocator.IsRegistered<IDataExportService>())
|
|||
|
|
{
|
|||
|
|
ServiceLocator.Register<IDataExportService>(new DataExportService());
|
|||
|
|
}
|
|||
|
|
if (!ServiceLocator.IsRegistered<IPatientInfoService>())
|
|||
|
|
{
|
|||
|
|
ServiceLocator.Register<IPatientInfoService>(new PatientInfoService());
|
|||
|
|
}
|
|||
|
|
// if (!ServiceLocator.IsRegistered<IDataService>())
|
|||
|
|
// {
|
|||
|
|
// ServiceLocator.Register<IDataService>(_dataService);
|
|||
|
|
// }
|
|||
|
|
|
|||
|
|
// 注册患者会话服务
|
|||
|
|
if (!ServiceLocator.IsRegistered<PatientSessionService>())
|
|||
|
|
{
|
|||
|
|
ServiceLocator.Register<PatientSessionService>(new PatientSessionService());
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void OnDestroy()
|
|||
|
|
{
|
|||
|
|
// 取消注册日志回调
|
|||
|
|
Application.logMessageReceived -= HandleUnityLogs;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 处理Unity日志,实现网络错误限流
|
|||
|
|
/// </summary>
|
|||
|
|
private void HandleUnityLogs(string logString, string stackTrace, LogType type)
|
|||
|
|
{
|
|||
|
|
// 只处理Error和Exception类型的日志
|
|||
|
|
if (type != LogType.Error && type != LogType.Exception)
|
|||
|
|
return;
|
|||
|
|
|
|||
|
|
// 检测是否为网络相关错误
|
|||
|
|
bool isNetworkError = logString.Contains("Network is unreachable") ||
|
|||
|
|
logString.Contains("network") ||
|
|||
|
|
logString.Contains("Network");
|
|||
|
|
|
|||
|
|
if (!isNetworkError)
|
|||
|
|
return;
|
|||
|
|
|
|||
|
|
// 网络错误计数
|
|||
|
|
_networkErrorCount++;
|
|||
|
|
|
|||
|
|
// 每60秒记录一次,避免日志刷屏
|
|||
|
|
if (Time.time - _lastNetworkErrorLogTime >= NETWORK_ERROR_LOG_INTERVAL)
|
|||
|
|
{
|
|||
|
|
Debug.Log($"[DCXManager] Unity底层网络检查(已忽略): {logString}");
|
|||
|
|
_lastNetworkErrorLogTime = Time.time;
|
|||
|
|
|
|||
|
|
#if UNITY_ANDROID && !UNITY_EDITOR
|
|||
|
|
AndroidFileLogger.Instance?.LogInfo("Network",
|
|||
|
|
$"Unity网络错误(过去{NETWORK_ERROR_LOG_INTERVAL}秒): {_networkErrorCount}次");
|
|||
|
|
|
|||
|
|
// 记录详细信息以便调试
|
|||
|
|
if (_networkErrorCount == 1)
|
|||
|
|
{
|
|||
|
|
AndroidFileLogger.Instance?.LogInfo("Network",
|
|||
|
|
$"首次网络错误详情: {logString}");
|
|||
|
|
}
|
|||
|
|
#endif
|
|||
|
|
|
|||
|
|
// 重置计数器
|
|||
|
|
_networkErrorCount = 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 注意:不触发GC,不做其他重操作
|
|||
|
|
// 网络错误是Unity Native层行为,不影响串口通信
|
|||
|
|
}
|
|||
|
|
}
|