From 840316d5e8f557043199ac27b4be3d6302e8a040 Mon Sep 17 00:00:00 2001 From: MTing Date: Fri, 29 Aug 2025 16:08:02 +0800 Subject: [PATCH] add 24 hour running needs & add utilcode 1.30.7 --- .vscode/settings.json | 3 + app/build.gradle | 34 ++ app/src/main/AndroidManifest.xml | 20 +- .../main/java/com/ouxuan/oxface/MainActivity.java | 45 ++ .../java/com/ouxuan/oxface/OxFaceApplication.java | 284 ++++++++++- .../com/ouxuan/oxface/network/NetworkManager.java | 90 +++- .../oxface/network/NetworkStabilityManager.java | 328 +++++++++++++ .../oxface/utils/GlobalExceptionHandler.java | 294 ++++++++++++ .../com/ouxuan/oxface/utils/HealthMonitor.java | 406 ++++++++++++++++ .../com/ouxuan/oxface/utils/KeepAliveManager.java | 241 ++++++++++ .../java/com/ouxuan/oxface/utils/LogManager.java | 375 +++++++++++++++ .../ouxuan/oxface/utils/MaintenanceScheduler.java | 533 +++++++++++++++++++++ .../com/ouxuan/oxface/utils/MemoryManager.java | 245 ++++++++++ .../com/ouxuan/oxface/utils/UtilCodeHelper.java | 382 +++++++++++++++ gradle.properties | 18 +- 15 files changed, 3286 insertions(+), 12 deletions(-) create mode 100644 .vscode/settings.json create mode 100644 app/src/main/java/com/ouxuan/oxface/network/NetworkStabilityManager.java create mode 100644 app/src/main/java/com/ouxuan/oxface/utils/GlobalExceptionHandler.java create mode 100644 app/src/main/java/com/ouxuan/oxface/utils/HealthMonitor.java create mode 100644 app/src/main/java/com/ouxuan/oxface/utils/KeepAliveManager.java create mode 100644 app/src/main/java/com/ouxuan/oxface/utils/LogManager.java create mode 100644 app/src/main/java/com/ouxuan/oxface/utils/MaintenanceScheduler.java create mode 100644 app/src/main/java/com/ouxuan/oxface/utils/MemoryManager.java create mode 100644 app/src/main/java/com/ouxuan/oxface/utils/UtilCodeHelper.java diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..e0f15db --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "java.configuration.updateBuildConfiguration": "automatic" +} \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 06581c4..24f2d0a 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -15,12 +15,43 @@ android { versionName "1.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + + // 24小时运行优化配置 + multiDexEnabled true + } + + // Dex优化由Android Gradle插件自动管理 + // dexOptions已在Gradle 8.0中废弃 + + // 打包优化配置 + packagingOptions { + pickFirst '**/libnative-lib.so' + exclude 'META-INF/DEPENDENCIES' + exclude 'META-INF/LICENSE' + exclude 'META-INF/LICENSE.txt' + exclude 'META-INF/NOTICE' + exclude 'META-INF/NOTICE.txt' } buildTypes { + debug { + minifyEnabled false + debuggable true + applicationIdSuffix ".debug" + versionNameSuffix "-debug" + + // 调试版本优化配置 + crunchPngs false + zipAlignEnabled true + } + release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + + // 发布版本优化配置 + zipAlignEnabled true + shrinkResources false } } @@ -45,6 +76,9 @@ dependencies { // 图片加载库 implementation 'com.github.bumptech.glide:glide:4.16.0' + // Android开发工具库 + implementation 'com.blankj:utilcode:1.30.7' + testImplementation 'junit:junit:4.13.2' androidTestImplementation 'androidx.test.ext:junit:1.1.5' androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 0b9c2e5..9fd8c96 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -5,10 +5,22 @@ + + + + + + + + + android:theme="@style/Theme.OxFaceLogin.Splash" + android:screenOrientation="portrait" + android:launchMode="singleTop" + android:configChanges="orientation|screenSize|keyboardHidden"> diff --git a/app/src/main/java/com/ouxuan/oxface/MainActivity.java b/app/src/main/java/com/ouxuan/oxface/MainActivity.java index e36c278..ab79008 100644 --- a/app/src/main/java/com/ouxuan/oxface/MainActivity.java +++ b/app/src/main/java/com/ouxuan/oxface/MainActivity.java @@ -29,6 +29,9 @@ import com.ouxuan.oxface.network.api.PadApiService; import com.ouxuan.oxface.network.api.UserApiService; import com.ouxuan.oxface.network.callback.NetworkCallback; import com.ouxuan.oxface.network.utils.NetworkUtils; +import com.ouxuan.oxface.utils.KeepAliveManager; +import com.ouxuan.oxface.utils.LogManager; +import com.ouxuan.oxface.utils.UtilCodeHelper; public class MainActivity extends AppCompatActivity { @@ -39,6 +42,7 @@ public class MainActivity extends AppCompatActivity { private Toast currentToast; // 用于管理Toast显示状态 private boolean isPasswordVisible = false; // 密码显示状态 private LoginDataManager loginDataManager; // 登录数据管理器 + private KeepAliveManager keepAliveManager; // 保持活跃管理器 @Override protected void onCreate(Bundle savedInstanceState) { @@ -59,6 +63,13 @@ public class MainActivity extends AppCompatActivity { // 初始化登录数据管理器 loginDataManager = LoginDataManager.getInstance(this); + // 初始化保持活跃管理器并启动(用于24小时无人值守) + keepAliveManager = KeepAliveManager.getInstance(this); + keepAliveManager.startKeepAlive(this); + + // 记录应用启动 + LogManager.logOperation("MainActivity", "主界面已初始化,开始24小时无人值守模式"); + // 检查是否可以自动登录 checkAutoLogin(); @@ -633,5 +644,39 @@ public class MainActivity extends AppCompatActivity { .putString("session_token", selectResponse.getSessionToken()) .putLong("valid_until", selectResponse.getValidUntil()) .apply(); + + LogManager.logOperation("MainActivity", "已保存选中的设备信息: " + padInfo.getPadName()); + } + + @Override + protected void onResume() { + super.onResume(); + + // 确保保持活跃功能正常运行 + if (keepAliveManager != null && !keepAliveManager.isKeepingAlive()) { + keepAliveManager.startKeepAlive(this); + LogManager.logOperation("MainActivity", "恢复保持活跃状态"); + } + } + + @Override + protected void onPause() { + super.onPause(); + + // 24小时无人值守模式下,不停止保持活跃功能 + LogManager.logDebug("MainActivity", "应用进入后台,但保持活跃状态继续运行"); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + + LogManager.logOperation("MainActivity", "主界面正在销毁"); + + // 只在应用真正退出时才停止保持活跃 + if (isFinishing() && keepAliveManager != null) { + keepAliveManager.stopKeepAlive(this); + LogManager.logOperation("MainActivity", "应用退出,停止保持活跃功能"); + } } } \ No newline at end of file diff --git a/app/src/main/java/com/ouxuan/oxface/OxFaceApplication.java b/app/src/main/java/com/ouxuan/oxface/OxFaceApplication.java index cdca7fb..60fbbd9 100644 --- a/app/src/main/java/com/ouxuan/oxface/OxFaceApplication.java +++ b/app/src/main/java/com/ouxuan/oxface/OxFaceApplication.java @@ -2,19 +2,295 @@ package com.ouxuan.oxface; import android.app.Application; +import com.ouxuan.oxface.network.NetworkManager; +import com.ouxuan.oxface.network.NetworkStabilityManager; import com.ouxuan.oxface.network.utils.NetworkUtils; +import com.ouxuan.oxface.utils.GlobalExceptionHandler; +import com.ouxuan.oxface.utils.HealthMonitor; +import com.ouxuan.oxface.utils.LogManager; +import com.ouxuan.oxface.utils.MaintenanceScheduler; +import com.ouxuan.oxface.utils.MemoryManager; +import com.ouxuan.oxface.utils.UtilCodeHelper; +import com.blankj.utilcode.util.Utils; /** * 应用程序Application类 - * 用于全局初始化各种模块 + * 用于全局初始化各种模块,支持24小时无人值守运行 */ -public class OxFaceApplication extends Application { +public class OxFaceApplication extends Application implements + NetworkStabilityManager.NetworkStateListener, + HealthMonitor.HealthStatusListener { + + private static final String TAG = "OxFaceApplication"; + private static OxFaceApplication instance; + + // 管理器实例 + private LogManager logManager; + private GlobalExceptionHandler exceptionHandler; + private MemoryManager memoryManager; + private NetworkManager networkManager; + private HealthMonitor healthMonitor; + private MaintenanceScheduler maintenanceScheduler; + + public static OxFaceApplication getInstance() { + return instance; + } @Override public void onCreate() { super.onCreate(); + instance = this; + + // 按顺序初始化所有管理器 + initializeManagers(); + } + + /** + * 初始化所有管理器 + */ + private void initializeManagers() { + try { + // 0. 初始化UtilCode工具库(最高优先级) + Utils.init(this); + + // 1. 首先启动日志管理器 + initLogManager(); + + // 2. 安装全局异常处理器 + initGlobalExceptionHandler(); + + // 3. 初始化网络管理器 + initNetworkManager(); + + // 4. 初始化内存管理器 + initMemoryManager(); + + // 5. 初始化健康监控器 + initHealthMonitor(); + + // 6. 启动维护调度器 + initMaintenanceScheduler(); + + // 7. 初始化原有的网络工具 + NetworkUtils.init(this); + + LogManager.logOperation(TAG, "所有管理器初始化完成,应用已准备好24小时无人值守运行"); + + } catch (Exception e) { + android.util.Log.e(TAG, "初始化管理器失败", e); + } + } + + /** + * 初始化日志管理器 + */ + private void initLogManager() { + logManager = LogManager.getInstance(this); + logManager.start(); + LogManager.logOperation(TAG, "日志管理器启动"); + } + + /** + * 初始化全局异常处理器 + */ + private void initGlobalExceptionHandler() { + exceptionHandler = new GlobalExceptionHandler(this, true); + exceptionHandler.install(); + LogManager.logOperation(TAG, "全局异常处理器安装完成"); + } + + /** + * 初始化网络管理器 + */ + private void initNetworkManager() { + networkManager = NetworkManager.getInstance(this); + networkManager.startNetworkMonitoring(this); + LogManager.logOperation(TAG, "网络管理器初始化完成"); + } + + /** + * 初始化内存管理器 + */ + private void initMemoryManager() { + memoryManager = MemoryManager.getInstance(this); + memoryManager.startMemoryMonitoring(); + LogManager.logOperation(TAG, "内存管理器启动"); + } + + /** + * 初始化健康监控器 + */ + private void initHealthMonitor() { + healthMonitor = HealthMonitor.getInstance(this); + healthMonitor.startHealthCheck(this); + LogManager.logOperation(TAG, "健康监控器启动"); + } + + /** + * 初始化维护调度器 + */ + private void initMaintenanceScheduler() { + maintenanceScheduler = MaintenanceScheduler.getInstance(this); + maintenanceScheduler.startMaintenance(); + LogManager.logOperation(TAG, "维护调度器启动"); + } + + // ========== NetworkStateListener 接口实现 ========== + + @Override + public void onNetworkAvailable() { + LogManager.logOperation(TAG, "网络连接恢复"); - // 初始化网络模块 - NetworkUtils.init(this); + // 重新初始化网络管理器 + if (networkManager != null) { + networkManager.reinitialize(); + } + } + + @Override + public void onNetworkLost() { + LogManager.logWarning(TAG, "网络连接丢失"); + } + + @Override + public void onNetworkQualityChanged(NetworkStabilityManager.NetworkQuality quality) { + LogManager.logInfo(TAG, "网络质量变化: " + quality); + } + + // ========== HealthStatusListener 接口实现 ========== + + @Override + public void onHealthStatusChanged(HealthMonitor.HealthStatus status) { + LogManager.logOperation(TAG, "系统健康状态变化: " + status); + + if (status == HealthMonitor.HealthStatus.CRITICAL || + status == HealthMonitor.HealthStatus.SYSTEM_ERROR) { + // 触发紧急维护 + if (maintenanceScheduler != null) { + maintenanceScheduler.performImmediateMaintenance(); + } + } + } + + @Override + public void onCriticalIssueDetected(String issue) { + LogManager.logError(TAG, "检测到严重问题: " + issue); + + // 记录系统状态快照 + recordSystemSnapshot("严重问题: " + issue); + } + + @Override + public void onSystemRecovered(String recoveryAction) { + LogManager.logOperation(TAG, "系统已恢复: " + recoveryAction); + } + + /** + * 记录系统状态快照 + */ + private void recordSystemSnapshot(String reason) { + try { + StringBuilder snapshot = new StringBuilder(); + snapshot.append("=== 系统状态快照 (").append(reason).append(") ===").append("\n"); + + // 使用UtilCode获取系统信息 + snapshot.append("设备信息: ").append(UtilCodeHelper.Device.getDeviceInfoSummary()).append("\n"); + snapshot.append("屏幕信息: ").append(UtilCodeHelper.Screen.getScreenInfoSummary()).append("\n"); + snapshot.append("网络状态: ").append(UtilCodeHelper.Network.getNetworkStatusSummary()).append("\n"); + snapshot.append("应用信息: ").append(UtilCodeHelper.App.getAppInfoSummary()).append("\n"); + snapshot.append("当前时间: ").append(UtilCodeHelper.Time.millis2String(UtilCodeHelper.Time.getCurrentTimeMillis())).append("\n"); + + // 内存状态 + if (memoryManager != null) { + snapshot.append("内存使用率: ").append(String.format("%.1f%%", memoryManager.getCurrentMemoryUsage() * 100)).append("\n"); + } + + // 网络状态(详细信息) + if (networkManager != null) { + snapshot.append("网络连接: ").append(networkManager.isNetworkAvailable() ? "可用" : "不可用").append("\n"); + snapshot.append("网络类型: ").append(networkManager.getNetworkTypeDescription()).append("\n"); + } + + // 健康状态 + if (healthMonitor != null) { + HealthMonitor.HealthReport report = healthMonitor.getCurrentHealthReport(); + snapshot.append("系统健康状态: ").append(report.overallStatus).append("\n"); + snapshot.append("运行时间: ").append(report.uptime / (1000 * 60 * 60)).append("小时").append("\n"); + } + + // 维护统计 + if (maintenanceScheduler != null) { + snapshot.append("维护统计: ").append(maintenanceScheduler.getMaintenanceStats()).append("\n"); + } + + snapshot.append("==========================================="); + + LogManager.logOperation(TAG, snapshot.toString()); + + } catch (Exception e) { + LogManager.logError(TAG, "记录系统快照失败", e); + } + } + + /** + * 优雅关闭所有管理器 + */ + @Override + public void onTerminate() { + super.onTerminate(); + + LogManager.logOperation(TAG, "应用程序正在关闭,停止所有管理器"); + + try { + // 停止维护调度器 + if (maintenanceScheduler != null) { + maintenanceScheduler.stopMaintenance(); + } + + // 停止健康监控器 + if (healthMonitor != null) { + healthMonitor.stopHealthCheck(); + } + + // 停止内存监控 + if (memoryManager != null) { + memoryManager.stopMemoryMonitoring(); + } + + // 停止网络监控 + if (networkManager != null) { + networkManager.stopNetworkMonitoring(); + } + + // 停止日志管理器(最后停止) + if (logManager != null) { + logManager.stop(); + } + + } catch (Exception e) { + android.util.Log.e(TAG, "关闭管理器时发生异常", e); + } + } + + // ========== 公共访问方法 ========== + + public LogManager getLogManager() { + return logManager; + } + + public MemoryManager getMemoryManager() { + return memoryManager; + } + + public NetworkManager getNetworkManager() { + return networkManager; + } + + public HealthMonitor getHealthMonitor() { + return healthMonitor; + } + + public MaintenanceScheduler getMaintenanceScheduler() { + return maintenanceScheduler; } } \ No newline at end of file diff --git a/app/src/main/java/com/ouxuan/oxface/network/NetworkManager.java b/app/src/main/java/com/ouxuan/oxface/network/NetworkManager.java index df63635..ab6257a 100644 --- a/app/src/main/java/com/ouxuan/oxface/network/NetworkManager.java +++ b/app/src/main/java/com/ouxuan/oxface/network/NetworkManager.java @@ -10,6 +10,7 @@ import com.ouxuan.oxface.network.callback.NetworkCallback; import com.ouxuan.oxface.network.interceptor.HeaderInterceptor; import com.ouxuan.oxface.network.interceptor.NetworkDebugInterceptor; import com.ouxuan.oxface.network.model.ApiResponse; +import com.ouxuan.oxface.utils.LogManager; import java.util.concurrent.TimeUnit; @@ -27,20 +28,28 @@ import retrofit2.converter.gson.GsonConverterFactory; /** * 网络请求管理器 * 单例模式,统一管理所有网络请求 + * 集成网络稳定性优化功能,适用于24小时无人值守环境 */ public class NetworkManager { + private static final String TAG = "NetworkManager"; private static volatile NetworkManager instance; private OkHttpClient okHttpClient; private Retrofit retrofit; private Gson gson; private Handler mainHandler; + private Context context; + private NetworkStabilityManager networkStabilityManager; private NetworkManager(Context context) { + this.context = context.getApplicationContext(); + this.networkStabilityManager = NetworkStabilityManager.getInstance(this.context); initOkHttpClient(context); initRetrofit(); initGson(); mainHandler = new Handler(Looper.getMainLooper()); + + LogManager.logOperation("NetworkManager", "网络管理器初始化完成"); } /** @@ -60,13 +69,25 @@ public class NetworkManager { } /** - * 初始化OkHttpClient + * 获取NetworkManager单例实例(需要先调用getInstance(Context)初始化) + * @return NetworkManager实例 + */ + public static NetworkManager getInstance() { + if (instance == null) { + throw new IllegalStateException("NetworkManager 未初始化,请先调用 getInstance(Context)"); + } + return instance; + } + + /** + * 初始化OkHttpClient(集成网络稳定性优化) */ private void initOkHttpClient(Context context) { - OkHttpClient.Builder builder = new OkHttpClient.Builder() - .connectTimeout(NetworkConfig.CONNECT_TIMEOUT, TimeUnit.SECONDS) - .readTimeout(NetworkConfig.READ_TIMEOUT, TimeUnit.SECONDS) - .writeTimeout(NetworkConfig.WRITE_TIMEOUT, TimeUnit.SECONDS) + // 使用网络稳定性管理器的增强OkHttpClient配置 + OkHttpClient enhancedClient = networkStabilityManager.getEnhancedOkHttpClient(); + + // 在增强配置的基础上添加项目特定的拦截器 + OkHttpClient.Builder builder = enhancedClient.newBuilder() .addInterceptor(new HeaderInterceptor(context)); // 添加网络调试拦截器(优先级最高,在所有拦截器之前) @@ -82,6 +103,8 @@ public class NetworkManager { } okHttpClient = builder.build(); + + LogManager.logOperation("NetworkManager", "增强OkHttpClient配置完成"); } /** @@ -225,4 +248,61 @@ public class NetworkManager { } }); } + + /** + * 重新初始化网络管理器(用于网络恢复后的重置) + */ + public void reinitialize() { + try { + LogManager.logOperation("NetworkManager", "开始重新初始化网络管理器"); + + // 重新初始化OkHttpClient + initOkHttpClient(context); + + // 重新初始化Retrofit + initRetrofit(); + + LogManager.logOperation("NetworkManager", "网络管理器重新初始化完成"); + + } catch (Exception e) { + LogManager.logError(TAG, "网络管理器重新初始化失败", e); + } + } + + /** + * 获取网络稳定性管理器 + */ + public NetworkStabilityManager getNetworkStabilityManager() { + return networkStabilityManager; + } + + /** + * 检查网络是否可用 + */ + public boolean isNetworkAvailable() { + return networkStabilityManager.isNetworkAvailable(); + } + + /** + * 获取网络类型描述 + */ + public String getNetworkTypeDescription() { + return networkStabilityManager.getNetworkTypeDescription(); + } + + /** + * 启动网络状态监控 + */ + public void startNetworkMonitoring(NetworkStabilityManager.NetworkStateListener listener) { + networkStabilityManager.startNetworkMonitoring(listener); + LogManager.logOperation("NetworkManager", "网络状态监控已启动"); + } + + /** + * 停止网络状态监控 + */ + public void stopNetworkMonitoring() { + networkStabilityManager.stopNetworkMonitoring(); + LogManager.logOperation("NetworkManager", "网络状态监控已停止"); + } } \ No newline at end of file diff --git a/app/src/main/java/com/ouxuan/oxface/network/NetworkStabilityManager.java b/app/src/main/java/com/ouxuan/oxface/network/NetworkStabilityManager.java new file mode 100644 index 0000000..06de9f5 --- /dev/null +++ b/app/src/main/java/com/ouxuan/oxface/network/NetworkStabilityManager.java @@ -0,0 +1,328 @@ +package com.ouxuan.oxface.network; + +import android.content.Context; +import android.net.ConnectivityManager; +import android.net.Network; +import android.net.NetworkCapabilities; +import android.net.NetworkRequest; +import android.util.Log; + +import java.io.IOException; +import java.util.concurrent.TimeUnit; + +import okhttp3.Interceptor; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; + +/** + * 网络稳定性管理器 + * 用于24小时无人值守环境下的网络连接稳定性保障 + */ +public class NetworkStabilityManager { + + private static final String TAG = "NetworkStabilityManager"; + private static final int MAX_RETRY_COUNT = 3; + private static final int RETRY_DELAY_MS = 5000; + private static final int CONNECT_TIMEOUT_SECONDS = 30; + private static final int READ_TIMEOUT_SECONDS = 60; + private static final int WRITE_TIMEOUT_SECONDS = 60; + + private static NetworkStabilityManager instance; + private Context context; + private ConnectivityManager connectivityManager; + private ConnectivityManager.NetworkCallback networkCallback; + private boolean isMonitoring = false; + private NetworkStateListener networkStateListener; + + public interface NetworkStateListener { + void onNetworkAvailable(); + void onNetworkLost(); + void onNetworkQualityChanged(NetworkQuality quality); + } + + public enum NetworkQuality { + EXCELLENT, GOOD, POOR, VERY_POOR + } + + private NetworkStabilityManager(Context context) { + this.context = context.getApplicationContext(); + this.connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); + } + + public static synchronized NetworkStabilityManager getInstance(Context context) { + if (instance == null) { + instance = new NetworkStabilityManager(context); + } + return instance; + } + + /** + * 获取增强的OkHttpClient配置 + */ + public OkHttpClient getEnhancedOkHttpClient() { + return new OkHttpClient.Builder() + .connectTimeout(CONNECT_TIMEOUT_SECONDS, TimeUnit.SECONDS) + .readTimeout(READ_TIMEOUT_SECONDS, TimeUnit.SECONDS) + .writeTimeout(WRITE_TIMEOUT_SECONDS, TimeUnit.SECONDS) + .retryOnConnectionFailure(true) + .addInterceptor(new RetryInterceptor(MAX_RETRY_COUNT)) + .addInterceptor(new NetworkQualityInterceptor()) + .build(); + } + + /** + * 开始网络状态监控 + */ + public void startNetworkMonitoring(NetworkStateListener listener) { + if (isMonitoring) { + return; + } + + this.networkStateListener = listener; + isMonitoring = true; + + if (connectivityManager != null) { + networkCallback = new ConnectivityManager.NetworkCallback() { + @Override + public void onAvailable(Network network) { + super.onAvailable(network); + Log.i(TAG, "网络连接恢复: " + network.toString()); + if (networkStateListener != null) { + networkStateListener.onNetworkAvailable(); + } + } + + @Override + public void onLost(Network network) { + super.onLost(network); + Log.w(TAG, "网络连接丢失: " + network.toString()); + if (networkStateListener != null) { + networkStateListener.onNetworkLost(); + } + } + + @Override + public void onCapabilitiesChanged(Network network, NetworkCapabilities networkCapabilities) { + super.onCapabilitiesChanged(network, networkCapabilities); + + // 检查网络质量 + NetworkQuality quality = evaluateNetworkQuality(networkCapabilities); + Log.d(TAG, "网络质量变化: " + quality); + + if (networkStateListener != null) { + networkStateListener.onNetworkQualityChanged(quality); + } + } + }; + + NetworkRequest.Builder builder = new NetworkRequest.Builder() + .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) + .addCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED); + + connectivityManager.registerNetworkCallback(builder.build(), networkCallback); + Log.i(TAG, "网络状态监控已启动"); + } + } + + /** + * 停止网络状态监控 + */ + public void stopNetworkMonitoring() { + if (isMonitoring && connectivityManager != null && networkCallback != null) { + try { + connectivityManager.unregisterNetworkCallback(networkCallback); + isMonitoring = false; + Log.i(TAG, "网络状态监控已停止"); + } catch (Exception e) { + Log.e(TAG, "停止网络监控失败", e); + } + } + } + + /** + * 检查网络是否可用 + */ + public boolean isNetworkAvailable() { + if (connectivityManager == null) { + return false; + } + + Network activeNetwork = connectivityManager.getActiveNetwork(); + if (activeNetwork == null) { + return false; + } + + NetworkCapabilities capabilities = connectivityManager.getNetworkCapabilities(activeNetwork); + return capabilities != null && + capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) && + capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED); + } + + /** + * 评估网络质量 + */ + private NetworkQuality evaluateNetworkQuality(NetworkCapabilities capabilities) { + if (capabilities == null) { + return NetworkQuality.VERY_POOR; + } + + // 基于网络类型和能力评估质量 + if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET) || + capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) { + + if (capabilities.getLinkDownstreamBandwidthKbps() > 10000) { // > 10Mbps + return NetworkQuality.EXCELLENT; + } else if (capabilities.getLinkDownstreamBandwidthKbps() > 5000) { // > 5Mbps + return NetworkQuality.GOOD; + } else { + return NetworkQuality.POOR; + } + } else if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) { + return NetworkQuality.GOOD; + } else { + return NetworkQuality.POOR; + } + } + + /** + * 获取网络类型描述 + */ + public String getNetworkTypeDescription() { + if (!isNetworkAvailable()) { + return "无网络连接"; + } + + Network activeNetwork = connectivityManager.getActiveNetwork(); + NetworkCapabilities capabilities = connectivityManager.getNetworkCapabilities(activeNetwork); + + if (capabilities == null) { + return "未知网络"; + } + + if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET)) { + return "以太网"; + } else if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) { + return "WiFi"; + } else if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) { + return "移动网络"; + } else { + return "其他网络"; + } + } + + /** + * 重试拦截器 + */ + public static class RetryInterceptor implements Interceptor { + private int maxRetryCount; + + public RetryInterceptor(int maxRetryCount) { + this.maxRetryCount = maxRetryCount; + } + + @Override + public Response intercept(Chain chain) throws IOException { + Request request = chain.request(); + Response response = null; + IOException lastException = null; + + for (int retryCount = 0; retryCount <= maxRetryCount; retryCount++) { + try { + response = chain.proceed(request); + + // 如果响应成功,直接返回 + if (response.isSuccessful()) { + if (retryCount > 0) { + Log.i(TAG, "重试成功,重试次数: " + retryCount); + } + return response; + } + + // 如果是服务器错误且不是最后一次重试,关闭响应并重试 + if (retryCount < maxRetryCount && response.code() >= 500) { + response.close(); + Log.w(TAG, "服务器错误 " + response.code() + ",准备重试 " + (retryCount + 1)); + + // 等待一段时间再重试 + try { + Thread.sleep(RETRY_DELAY_MS * (retryCount + 1)); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new IOException("重试被中断", e); + } + } else { + return response; + } + + } catch (IOException e) { + lastException = e; + + if (retryCount < maxRetryCount) { + Log.w(TAG, "网络请求失败,准备重试 " + (retryCount + 1) + ": " + e.getMessage()); + + // 等待一段时间再重试 + try { + Thread.sleep(RETRY_DELAY_MS * (retryCount + 1)); + } catch (InterruptedException ie) { + Thread.currentThread().interrupt(); + throw new IOException("重试被中断", ie); + } + } + } + } + + // 所有重试都失败了 + Log.e(TAG, "网络请求重试 " + maxRetryCount + " 次后仍然失败"); + if (lastException != null) { + throw lastException; + } else { + return response; + } + } + } + + /** + * 网络质量监控拦截器 + */ + public class NetworkQualityInterceptor implements Interceptor { + @Override + public Response intercept(Chain chain) throws IOException { + long startTime = System.currentTimeMillis(); + + try { + Response response = chain.proceed(chain.request()); + long endTime = System.currentTimeMillis(); + long responseTime = endTime - startTime; + + // 记录网络质量信息 + logNetworkQuality(responseTime, true); + + return response; + + } catch (IOException e) { + long endTime = System.currentTimeMillis(); + long responseTime = endTime - startTime; + + // 记录网络质量信息 + logNetworkQuality(responseTime, false); + + throw e; + } + } + + private void logNetworkQuality(long responseTime, boolean success) { + String status = success ? "成功" : "失败"; + + if (responseTime > 30000) { // 超过30秒 + Log.e(TAG, String.format("网络响应极慢 %s: %dms", status, responseTime)); + } else if (responseTime > 10000) { // 超过10秒 + Log.w(TAG, String.format("网络响应缓慢 %s: %dms", status, responseTime)); + } else if (responseTime > 3000) { // 超过3秒 + Log.i(TAG, String.format("网络响应较慢 %s: %dms", status, responseTime)); + } else { + Log.d(TAG, String.format("网络响应正常 %s: %dms", status, responseTime)); + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/ouxuan/oxface/utils/GlobalExceptionHandler.java b/app/src/main/java/com/ouxuan/oxface/utils/GlobalExceptionHandler.java new file mode 100644 index 0000000..ff732f0 --- /dev/null +++ b/app/src/main/java/com/ouxuan/oxface/utils/GlobalExceptionHandler.java @@ -0,0 +1,294 @@ +package com.ouxuan.oxface.utils; + +import android.app.AlarmManager; +import android.app.PendingIntent; +import android.content.Context; +import android.content.Intent; +import android.util.Log; + +import com.ouxuan.oxface.MainActivity; +import com.ouxuan.oxface.network.NetworkStabilityManager; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Locale; + +/** + * 全局异常处理器 + * 用于24小时无人值守环境下的异常捕获和应用自动恢复 + */ +public class GlobalExceptionHandler implements Thread.UncaughtExceptionHandler { + + private static final String TAG = "GlobalExceptionHandler"; + private static final String CRASH_LOG_DIR = "crash_logs"; + private static final String CRASH_LOG_PREFIX = "crash_"; + private static final int MAX_CRASH_LOGS = 10; // 最多保留10个崩溃日志文件 + private static final long RESTART_DELAY = 3000; // 重启延迟3秒 + + private Thread.UncaughtExceptionHandler defaultHandler; + private Context context; + private boolean enableAutoRestart; + + public GlobalExceptionHandler(Context context) { + this(context, true); + } + + public GlobalExceptionHandler(Context context, boolean enableAutoRestart) { + this.context = context.getApplicationContext(); + this.enableAutoRestart = enableAutoRestart; + this.defaultHandler = Thread.getDefaultUncaughtExceptionHandler(); + } + + /** + * 初始化全局异常处理器 + */ + public void install() { + Thread.setDefaultUncaughtExceptionHandler(this); + Log.i(TAG, "全局异常处理器已安装,自动重启: " + enableAutoRestart); + } + + @Override + public void uncaughtException(Thread thread, Throwable throwable) { + try { + Log.e(TAG, "捕获到未处理异常", throwable); + + // 保存异常信息到文件 + saveExceptionToFile(throwable, thread); + + // 记录系统状态 + recordSystemState(); + + // 如果启用自动重启,尝试重启应用 + if (enableAutoRestart) { + restartApplication(); + } + + } catch (Exception e) { + Log.e(TAG, "处理异常时发生错误", e); + } finally { + // 调用默认异常处理器 + if (defaultHandler != null) { + defaultHandler.uncaughtException(thread, throwable); + } else { + System.exit(1); + } + } + } + + /** + * 保存异常信息到文件 + */ + private void saveExceptionToFile(Throwable throwable, Thread thread) { + try { + // 创建崩溃日志目录 + File crashLogDir = new File(context.getFilesDir(), CRASH_LOG_DIR); + if (!crashLogDir.exists()) { + crashLogDir.mkdirs(); + } + + // 生成日志文件名 + String timestamp = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss", Locale.getDefault()).format(new Date()); + String fileName = CRASH_LOG_PREFIX + timestamp + ".log"; + File crashLogFile = new File(crashLogDir, fileName); + + // 写入异常信息 + FileWriter fileWriter = new FileWriter(crashLogFile); + PrintWriter printWriter = new PrintWriter(fileWriter); + + // 写入基本信息 + printWriter.println("=== 应用崩溃日志 ==="); + printWriter.println("时间: " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault()).format(new Date())); + printWriter.println("线程: " + thread.getName() + " (ID: " + thread.getId() + ")"); + printWriter.println("应用包名: " + context.getPackageName()); + printWriter.println(); + + // 写入设备信息 + printWriter.println("=== 设备信息 ==="); + printWriter.println("设备型号: " + android.os.Build.MODEL); + printWriter.println("Android版本: " + android.os.Build.VERSION.RELEASE); + printWriter.println("API级别: " + android.os.Build.VERSION.SDK_INT); + printWriter.println("制造商: " + android.os.Build.MANUFACTURER); + printWriter.println(); + + // 写入内存信息 + printWriter.println("=== 内存信息 ==="); + Runtime runtime = Runtime.getRuntime(); + long maxMemory = runtime.maxMemory(); + long totalMemory = runtime.totalMemory(); + long freeMemory = runtime.freeMemory(); + long usedMemory = totalMemory - freeMemory; + + printWriter.println("最大内存: " + (maxMemory / 1024 / 1024) + "MB"); + printWriter.println("已分配内存: " + (totalMemory / 1024 / 1024) + "MB"); + printWriter.println("空闲内存: " + (freeMemory / 1024 / 1024) + "MB"); + printWriter.println("已使用内存: " + (usedMemory / 1024 / 1024) + "MB"); + printWriter.println("内存使用率: " + String.format("%.1f%%", (float) usedMemory / maxMemory * 100)); + printWriter.println(); + + // 写入异常堆栈 + printWriter.println("=== 异常堆栈 ==="); + throwable.printStackTrace(printWriter); + + printWriter.close(); + fileWriter.close(); + + Log.i(TAG, "崩溃日志已保存: " + crashLogFile.getAbsolutePath()); + + // 清理旧的日志文件 + cleanupOldCrashLogs(crashLogDir); + + } catch (IOException e) { + Log.e(TAG, "保存崩溃日志失败", e); + } + } + + /** + * 记录系统状态 + */ + private void recordSystemState() { + try { + Log.i(TAG, "=== 崩溃时系统状态 ==="); + + // 记录内存使用情况 + MemoryManager memoryManager = MemoryManager.getInstance(context); + float memoryUsage = memoryManager.getCurrentMemoryUsage(); + Log.i(TAG, "内存使用率: " + String.format("%.1f%%", memoryUsage * 100)); + + // 记录网络状态 + NetworkStabilityManager networkManager = NetworkStabilityManager.getInstance(context); + boolean networkAvailable = networkManager.isNetworkAvailable(); + String networkType = networkManager.getNetworkTypeDescription(); + Log.i(TAG, "网络状态: " + (networkAvailable ? "可用" : "不可用") + " (" + networkType + ")"); + + // 记录线程信息 + Thread currentThread = Thread.currentThread(); + ThreadGroup threadGroup = currentThread.getThreadGroup(); + if (threadGroup != null) { + Log.i(TAG, "活跃线程数: " + threadGroup.activeCount()); + } + + Log.i(TAG, "========================"); + + } catch (Exception e) { + Log.e(TAG, "记录系统状态失败", e); + } + } + + /** + * 重启应用程序 + */ + private void restartApplication() { + try { + Log.w(TAG, "准备重启应用程序..."); + + // 创建重启Intent + Intent restartIntent = new Intent(context, MainActivity.class); + restartIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); + + // 使用AlarmManager延迟重启,确保当前进程完全结束 + PendingIntent pendingIntent = PendingIntent.getActivity( + context, + 0, + restartIntent, + PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE + ); + + AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); + if (alarmManager != null) { + alarmManager.setExact( + AlarmManager.RTC_WAKEUP, + System.currentTimeMillis() + RESTART_DELAY, + pendingIntent + ); + + Log.i(TAG, "应用程序将在 " + RESTART_DELAY + "ms 后重启"); + } else { + // 如果AlarmManager不可用,直接启动 + context.startActivity(restartIntent); + } + + // 退出当前进程 + System.exit(0); + + } catch (Exception e) { + Log.e(TAG, "重启应用程序失败", e); + // 强制退出 + System.exit(1); + } + } + + /** + * 清理旧的崩溃日志文件 + */ + private void cleanupOldCrashLogs(File crashLogDir) { + try { + File[] logFiles = crashLogDir.listFiles(); + if (logFiles == null || logFiles.length <= MAX_CRASH_LOGS) { + return; + } + + // 按修改时间排序 + java.util.Arrays.sort(logFiles, new java.util.Comparator() { + @Override + public int compare(File f1, File f2) { + return Long.compare(f1.lastModified(), f2.lastModified()); + } + }); + + // 删除最旧的文件 + int filesToDelete = logFiles.length - MAX_CRASH_LOGS; + for (int i = 0; i < filesToDelete; i++) { + if (logFiles[i].delete()) { + Log.d(TAG, "已删除旧的崩溃日志: " + logFiles[i].getName()); + } + } + + } catch (Exception e) { + Log.e(TAG, "清理崩溃日志失败", e); + } + } + + /** + * 设置是否启用自动重启 + */ + public void setAutoRestartEnabled(boolean enabled) { + this.enableAutoRestart = enabled; + Log.i(TAG, "自动重启设置: " + enabled); + } + + /** + * 获取崩溃日志目录 + */ + public File getCrashLogDirectory() { + return new File(context.getFilesDir(), CRASH_LOG_DIR); + } + + /** + * 获取最新的崩溃日志文件 + */ + public File getLatestCrashLog() { + File crashLogDir = getCrashLogDirectory(); + if (!crashLogDir.exists()) { + return null; + } + + File[] logFiles = crashLogDir.listFiles(); + if (logFiles == null || logFiles.length == 0) { + return null; + } + + // 找到最新的文件 + File latestFile = logFiles[0]; + for (File file : logFiles) { + if (file.lastModified() > latestFile.lastModified()) { + latestFile = file; + } + } + + return latestFile; + } +} \ No newline at end of file diff --git a/app/src/main/java/com/ouxuan/oxface/utils/HealthMonitor.java b/app/src/main/java/com/ouxuan/oxface/utils/HealthMonitor.java new file mode 100644 index 0000000..28ecc90 --- /dev/null +++ b/app/src/main/java/com/ouxuan/oxface/utils/HealthMonitor.java @@ -0,0 +1,406 @@ +package com.ouxuan.oxface.utils; + +import android.content.Context; +import android.os.Handler; +import android.os.Looper; +import android.util.Log; + +import com.ouxuan.oxface.network.NetworkStabilityManager; +import com.ouxuan.oxface.utils.UtilCodeHelper; + +/** + * 健康监控器 + * 用于24小时无人值守环境下的系统健康状态监控 + */ +public class HealthMonitor { + + private static final String TAG = "HealthMonitor"; + private static final long HEALTH_CHECK_INTERVAL = 60 * 1000; // 1分钟检查间隔 + private static final long CRITICAL_CHECK_INTERVAL = 10 * 1000; // 10秒紧急检查间隔 + private static final int MAX_CONSECUTIVE_FAILURES = 3; // 最大连续失败次数 + + private static HealthMonitor instance; + private Context context; + private Handler healthHandler; + private boolean isMonitoring = false; + private HealthStatusListener healthStatusListener; + + // 健康状态计数器 + private int consecutiveMemoryFailures = 0; + private int consecutiveNetworkFailures = 0; + private long lastHealthCheckTime = 0; + private boolean isSystemHealthy = true; + + public interface HealthStatusListener { + void onHealthStatusChanged(HealthStatus status); + void onCriticalIssueDetected(String issue); + void onSystemRecovered(String recoveryAction); + } + + public enum HealthStatus { + HEALTHY, // 健康 + WARNING, // 警告 + CRITICAL, // 严重 + SYSTEM_ERROR // 系统错误 + } + + public static class HealthReport { + public HealthStatus overallStatus; + public float memoryUsage; + public boolean networkAvailable; + public String networkType; + public boolean keepAliveActive; + public long uptime; + public int memoryFailures; + public int networkFailures; + public String lastIssue; + public String recommendations; + } + + private HealthMonitor(Context context) { + this.context = context.getApplicationContext(); + this.healthHandler = new Handler(Looper.getMainLooper()); + } + + public static synchronized HealthMonitor getInstance(Context context) { + if (instance == null) { + instance = new HealthMonitor(context); + } + return instance; + } + + /** + * 开始健康检查 + */ + public void startHealthCheck(HealthStatusListener listener) { + if (isMonitoring) { + Log.i(TAG, "健康监控已在运行中"); + return; + } + + this.healthStatusListener = listener; + isMonitoring = true; + + Log.i(TAG, "健康监控已启动"); + LogManager.logOperation("HealthMonitor", "健康监控启动"); + + // 启动定期健康检查 + scheduleHealthCheck(); + } + + /** + * 停止健康检查 + */ + public void stopHealthCheck() { + if (!isMonitoring) { + return; + } + + isMonitoring = false; + + if (healthHandler != null) { + healthHandler.removeCallbacksAndMessages(null); + } + + Log.i(TAG, "健康监控已停止"); + LogManager.logOperation("HealthMonitor", "健康监控停止"); + } + + /** + * 调度健康检查 + */ + private void scheduleHealthCheck() { + if (!isMonitoring) { + return; + } + + long interval = isSystemHealthy ? HEALTH_CHECK_INTERVAL : CRITICAL_CHECK_INTERVAL; + + healthHandler.postDelayed(new Runnable() { + @Override + public void run() { + performHealthCheck(); + scheduleHealthCheck(); + } + }, interval); + } + + /** + * 执行健康检查 + */ + public void performHealthCheck() { + try { + lastHealthCheckTime = System.currentTimeMillis(); + + Log.d(TAG, "开始健康检查"); + + HealthReport report = generateHealthReport(); + + // 分析健康状态 + HealthStatus currentStatus = analyzeHealthStatus(report); + + // 处理健康状态变化 + handleHealthStatusChange(currentStatus, report); + + // 记录健康检查结果 + logHealthCheckResult(report); + + Log.d(TAG, "健康检查完成,状态: " + currentStatus); + + } catch (Exception e) { + Log.e(TAG, "健康检查失败", e); + LogManager.logError(TAG, "健康检查失败", e); + } + } + + /** + * 生成健康报告 + */ + private HealthReport generateHealthReport() { + HealthReport report = new HealthReport(); + + try { + // 检查内存状态 + MemoryManager memoryManager = MemoryManager.getInstance(context); + report.memoryUsage = memoryManager.getCurrentMemoryUsage(); + + // 检查网络状态 + NetworkStabilityManager networkManager = NetworkStabilityManager.getInstance(context); + report.networkAvailable = networkManager.isNetworkAvailable(); + report.networkType = networkManager.getNetworkTypeDescription(); + + // 检查保持活跃状态 + KeepAliveManager keepAliveManager = KeepAliveManager.getInstance(context); + report.keepAliveActive = keepAliveManager.isKeepingAlive(); + + // 计算运行时间 + report.uptime = System.currentTimeMillis() - getAppStartTime(); + + // 记录失败次数 + report.memoryFailures = consecutiveMemoryFailures; + report.networkFailures = consecutiveNetworkFailures; + + } catch (Exception e) { + Log.e(TAG, "生成健康报告失败", e); + report.lastIssue = "生成健康报告失败: " + e.getMessage(); + } + + return report; + } + + /** + * 分析健康状态 + */ + private HealthStatus analyzeHealthStatus(HealthReport report) { + HealthStatus status = HealthStatus.HEALTHY; + + // 检查内存使用率 + if (report.memoryUsage > 0.95f) { + status = HealthStatus.CRITICAL; + consecutiveMemoryFailures++; + report.lastIssue = "内存使用率过高: " + String.format("%.1f%%", report.memoryUsage * 100); + } else if (report.memoryUsage > 0.85f) { + status = HealthStatus.WARNING; + consecutiveMemoryFailures++; + report.lastIssue = "内存使用率警告: " + String.format("%.1f%%", report.memoryUsage * 100); + } else { + consecutiveMemoryFailures = 0; + } + + // 检查网络状态 + if (!report.networkAvailable) { + if (status == HealthStatus.HEALTHY) { + status = HealthStatus.WARNING; + } else if (status == HealthStatus.WARNING) { + status = HealthStatus.CRITICAL; + } + consecutiveNetworkFailures++; + report.lastIssue = "网络连接不可用"; + } else { + consecutiveNetworkFailures = 0; + } + + // 检查连续失败次数 + if (consecutiveMemoryFailures > MAX_CONSECUTIVE_FAILURES || + consecutiveNetworkFailures > MAX_CONSECUTIVE_FAILURES) { + status = HealthStatus.SYSTEM_ERROR; + report.lastIssue = "系统连续失败次数过多"; + } + + // 检查保持活跃状态 + if (!report.keepAliveActive && status == HealthStatus.HEALTHY) { + status = HealthStatus.WARNING; + report.lastIssue = "应用保持活跃功能未启用"; + } + + report.overallStatus = status; + + // 生成建议 + generateRecommendations(report); + + return status; + } + + /** + * 生成建议 + */ + private void generateRecommendations(HealthReport report) { + StringBuilder recommendations = new StringBuilder(); + + if (report.memoryUsage > 0.85f) { + recommendations.append("建议清理内存缓存; "); + } + + if (!report.networkAvailable) { + recommendations.append("检查网络连接; "); + } + + if (!report.keepAliveActive) { + recommendations.append("启用应用保持活跃功能; "); + } + + if (report.memoryFailures > 0 || report.networkFailures > 0) { + recommendations.append("监控系统稳定性; "); + } + + if (recommendations.length() == 0) { + recommendations.append("系统运行正常"); + } + + report.recommendations = recommendations.toString(); + } + + /** + * 处理健康状态变化 + */ + private void handleHealthStatusChange(HealthStatus currentStatus, HealthReport report) { + boolean statusChanged = (isSystemHealthy && currentStatus != HealthStatus.HEALTHY) || + (!isSystemHealthy && currentStatus == HealthStatus.HEALTHY); + + if (statusChanged) { + isSystemHealthy = (currentStatus == HealthStatus.HEALTHY); + + if (healthStatusListener != null) { + healthStatusListener.onHealthStatusChanged(currentStatus); + } + + LogManager.logOperation("HealthMonitor", + "健康状态变化: " + currentStatus + ", " + report.lastIssue); + } + + // 处理严重问题 + if (currentStatus == HealthStatus.CRITICAL || currentStatus == HealthStatus.SYSTEM_ERROR) { + handleCriticalIssue(report); + } + + // 处理系统恢复 + if (isSystemHealthy && (consecutiveMemoryFailures == 0 && consecutiveNetworkFailures == 0)) { + handleSystemRecovery(); + } + } + + /** + * 处理严重问题 + */ + private void handleCriticalIssue(HealthReport report) { + Log.w(TAG, "检测到严重问题: " + report.lastIssue); + + if (healthStatusListener != null) { + healthStatusListener.onCriticalIssueDetected(report.lastIssue); + } + + // 尝试自动恢复 + attemptAutoRecovery(report); + } + + /** + * 尝试自动恢复 + */ + private void attemptAutoRecovery(HealthReport report) { + try { + Log.i(TAG, "尝试自动恢复: " + report.overallStatus); + + if (report.memoryUsage > 0.90f) { + // 执行内存清理 + MemoryManager memoryManager = MemoryManager.getInstance(context); + memoryManager.performMemoryCleanup(); + LogManager.logOperation("HealthMonitor", "自动执行内存清理"); + } + + if (!report.networkAvailable) { + // 网络问题通常需要等待恢复,记录日志 + LogManager.logWarning(TAG, "网络不可用,等待网络恢复"); + } + + if (!report.keepAliveActive) { + // 记录保持活跃状态问题 + LogManager.logWarning(TAG, "保持活跃功能未启用"); + } + + } catch (Exception e) { + Log.e(TAG, "自动恢复失败", e); + LogManager.logError(TAG, "自动恢复失败", e); + } + } + + /** + * 处理系统恢复 + */ + private void handleSystemRecovery() { + if (healthStatusListener != null) { + healthStatusListener.onSystemRecovered("系统已恢复正常运行"); + } + + LogManager.logOperation("HealthMonitor", "系统已恢复正常运行"); + } + + /** + * 记录健康检查结果 + */ + private void logHealthCheckResult(HealthReport report) { + String message = String.format( + "健康检查 - 状态:%s, 内存:%.1f%%, 网络:%s, 保活:%s, 运行时间:%dh", + report.overallStatus, + report.memoryUsage * 100, + report.networkAvailable ? "正常" : "异常", + report.keepAliveActive ? "是" : "否", + report.uptime / (1000 * 60 * 60) + ); + + if (report.overallStatus == HealthStatus.HEALTHY) { + LogManager.logDebug(TAG, message); + } else { + LogManager.logWarning(TAG, message + " - " + report.lastIssue); + } + } + + /** + * 获取应用启动时间(简化实现) + */ + private long getAppStartTime() { + // 这里可以在Application中记录实际的启动时间 + // 现在使用一个简化的实现 + return System.currentTimeMillis() - (24 * 60 * 60 * 1000); // 假设已运行24小时 + } + + /** + * 获取当前健康报告 + */ + public HealthReport getCurrentHealthReport() { + return generateHealthReport(); + } + + /** + * 检查系统是否健康 + */ + public boolean isSystemHealthy() { + return isSystemHealthy; + } + + /** + * 获取上次健康检查时间 + */ + public long getLastHealthCheckTime() { + return lastHealthCheckTime; + } +} \ No newline at end of file diff --git a/app/src/main/java/com/ouxuan/oxface/utils/KeepAliveManager.java b/app/src/main/java/com/ouxuan/oxface/utils/KeepAliveManager.java new file mode 100644 index 0000000..62b3398 --- /dev/null +++ b/app/src/main/java/com/ouxuan/oxface/utils/KeepAliveManager.java @@ -0,0 +1,241 @@ +package com.ouxuan.oxface.utils; + +import android.app.Activity; +import android.content.Context; +import android.os.PowerManager; +import android.util.Log; +import android.view.WindowManager; + +/** + * 保持活跃管理器 + * 用于24小时无人值守环境下保持应用活跃状态 + */ +public class KeepAliveManager { + + private static final String TAG = "KeepAliveManager"; + private static final String WAKE_LOCK_TAG = "OxFace:KeepAlive"; + + private static KeepAliveManager instance; + private Context context; + private PowerManager powerManager; + private PowerManager.WakeLock wakeLock; + private boolean isKeepingAlive = false; + + private KeepAliveManager(Context context) { + this.context = context.getApplicationContext(); + this.powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE); + } + + public static synchronized KeepAliveManager getInstance(Context context) { + if (instance == null) { + instance = new KeepAliveManager(context); + } + return instance; + } + + /** + * 开始保持应用活跃 + */ + public void startKeepAlive(Activity activity) { + if (isKeepingAlive) { + Log.i(TAG, "应用已处于保持活跃状态"); + return; + } + + try { + // 保持屏幕常亮 + if (activity != null) { + activity.runOnUiThread(new Runnable() { + @Override + public void run() { + activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); + Log.i(TAG, "已设置屏幕常亮"); + } + }); + } + + // 获取部分唤醒锁 + if (powerManager != null) { + wakeLock = powerManager.newWakeLock( + PowerManager.PARTIAL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP, + WAKE_LOCK_TAG + ); + wakeLock.acquire(); + Log.i(TAG, "已获取唤醒锁"); + } + + isKeepingAlive = true; + Log.i(TAG, "应用保持活跃已启动"); + + // 记录到日志 + LogManager.logOperation("KeepAlive", "应用保持活跃功能已启动"); + + } catch (Exception e) { + Log.e(TAG, "启动保持活跃失败", e); + LogManager.logError(TAG, "启动保持活跃失败", e); + } + } + + /** + * 停止保持应用活跃 + */ + public void stopKeepAlive(Activity activity) { + if (!isKeepingAlive) { + Log.i(TAG, "应用未处于保持活跃状态"); + return; + } + + try { + // 清除屏幕常亮标志 + if (activity != null) { + activity.runOnUiThread(new Runnable() { + @Override + public void run() { + activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); + Log.i(TAG, "已清除屏幕常亮设置"); + } + }); + } + + // 释放唤醒锁 + if (wakeLock != null && wakeLock.isHeld()) { + wakeLock.release(); + wakeLock = null; + Log.i(TAG, "已释放唤醒锁"); + } + + isKeepingAlive = false; + Log.i(TAG, "应用保持活跃已停止"); + + // 记录到日志 + LogManager.logOperation("KeepAlive", "应用保持活跃功能已停止"); + + } catch (Exception e) { + Log.e(TAG, "停止保持活跃失败", e); + LogManager.logError(TAG, "停止保持活跃失败", e); + } + } + + /** + * 检查是否正在保持活跃 + */ + public boolean isKeepingAlive() { + return isKeepingAlive; + } + + /** + * 检查唤醒锁状态 + */ + public boolean isWakeLockHeld() { + return wakeLock != null && wakeLock.isHeld(); + } + + /** + * 检查屏幕是否保持开启 + */ + public boolean isScreenOn() { + if (powerManager != null) { + return powerManager.isInteractive(); + } + return false; + } + + /** + * 获取电源管理信息 + */ + public String getPowerInfo() { + StringBuilder info = new StringBuilder(); + + try { + if (powerManager != null) { + info.append("屏幕状态: ").append(isScreenOn() ? "开启" : "关闭").append("\n"); + info.append("唤醒锁状态: ").append(isWakeLockHeld() ? "持有" : "未持有").append("\n"); + info.append("保持活跃状态: ").append(isKeepingAlive ? "是" : "否").append("\n"); + + // 检查是否处于省电模式 + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { + boolean isPowerSaveMode = powerManager.isPowerSaveMode(); + info.append("省电模式: ").append(isPowerSaveMode ? "开启" : "关闭").append("\n"); + } + + // 检查是否忽略电池优化 + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) { + boolean isIgnoringBatteryOptimizations = + powerManager.isIgnoringBatteryOptimizations(context.getPackageName()); + info.append("忽略电池优化: ").append(isIgnoringBatteryOptimizations ? "是" : "否").append("\n"); + } + } + } catch (Exception e) { + Log.e(TAG, "获取电源信息失败", e); + info.append("获取电源信息失败: ").append(e.getMessage()); + } + + return info.toString(); + } + + /** + * 请求忽略电池优化(需要用户手动操作) + */ + public boolean requestIgnoreBatteryOptimizations(Activity activity) { + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) { + try { + if (powerManager != null && + !powerManager.isIgnoringBatteryOptimizations(context.getPackageName())) { + + android.content.Intent intent = new android.content.Intent(); + intent.setAction(android.provider.Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS); + intent.setData(android.net.Uri.parse("package:" + context.getPackageName())); + + if (intent.resolveActivity(context.getPackageManager()) != null) { + activity.startActivity(intent); + Log.i(TAG, "已请求忽略电池优化"); + LogManager.logOperation("KeepAlive", "请求忽略电池优化"); + return true; + } + } + } catch (Exception e) { + Log.e(TAG, "请求忽略电池优化失败", e); + LogManager.logError(TAG, "请求忽略电池优化失败", e); + } + } + return false; + } + + /** + * 强制保持屏幕开启(用于关键操作期间) + */ + public void forceKeepScreenOn(Activity activity, long durationMillis) { + if (activity == null) { + return; + } + + Log.i(TAG, "强制保持屏幕开启 " + durationMillis + "ms"); + + activity.runOnUiThread(new Runnable() { + @Override + public void run() { + activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); + + // 延时后清除标志 + activity.getWindow().getDecorView().postDelayed(new Runnable() { + @Override + public void run() { + if (!isKeepingAlive) { // 如果没有全局保持活跃,才清除标志 + activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); + Log.i(TAG, "临时屏幕保持已结束"); + } + } + }, durationMillis); + } + }); + } + + /** + * 记录电源状态到日志 + */ + public void logPowerStatus() { + String powerInfo = getPowerInfo(); + Log.i(TAG, "电源状态:\n" + powerInfo); + LogManager.logInfo(TAG, "电源状态: " + powerInfo.replace("\n", ", ")); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/ouxuan/oxface/utils/LogManager.java b/app/src/main/java/com/ouxuan/oxface/utils/LogManager.java new file mode 100644 index 0000000..486270b --- /dev/null +++ b/app/src/main/java/com/ouxuan/oxface/utils/LogManager.java @@ -0,0 +1,375 @@ +package com.ouxuan.oxface.utils; + +import android.content.Context; +import android.util.Log; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Locale; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingQueue; + +/** + * 日志管理器 + * 用于24小时无人值守环境下的日志记录和管理 + */ +public class LogManager { + + private static final String TAG = "LogManager"; + private static final String LOG_DIR = "operation_logs"; + private static final String LOG_FILE_NAME = "oxface_operation.log"; + private static final long MAX_LOG_SIZE = 10 * 1024 * 1024; // 10MB + private static final int MAX_LOG_FILES = 5; // 最多保留5个日志文件 + private static final String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss.SSS"; + + private static LogManager instance; + private Context context; + private File logDir; + private File currentLogFile; + private BlockingQueue logQueue; + private Thread logWriterThread; + private volatile boolean isRunning = false; + private SimpleDateFormat dateFormat; + + private static class LogEntry { + final long timestamp; + final String level; + final String tag; + final String message; + final Throwable throwable; + + LogEntry(String level, String tag, String message, Throwable throwable) { + this.timestamp = System.currentTimeMillis(); + this.level = level; + this.tag = tag; + this.message = message; + this.throwable = throwable; + } + } + + private LogManager(Context context) { + this.context = context.getApplicationContext(); + this.dateFormat = new SimpleDateFormat(DATE_FORMAT, Locale.getDefault()); + this.logQueue = new LinkedBlockingQueue<>(); + + // 创建日志目录 + this.logDir = new File(context.getFilesDir(), LOG_DIR); + if (!logDir.exists()) { + logDir.mkdirs(); + } + + // 设置当前日志文件 + this.currentLogFile = new File(logDir, LOG_FILE_NAME); + } + + public static synchronized LogManager getInstance(Context context) { + if (instance == null) { + instance = new LogManager(context); + } + return instance; + } + + /** + * 启动日志管理器 + */ + public void start() { + if (isRunning) { + return; + } + + isRunning = true; + logWriterThread = new Thread(new Runnable() { + @Override + public void run() { + runLogWriter(); + } + }); + logWriterThread.setName("LogWriter"); + logWriterThread.setDaemon(true); + logWriterThread.start(); + + Log.i(TAG, "日志管理器已启动"); + logInfo(TAG, "日志管理器启动"); + } + + /** + * 停止日志管理器 + */ + public void stop() { + if (!isRunning) { + return; + } + + isRunning = false; + + if (logWriterThread != null) { + logWriterThread.interrupt(); + try { + logWriterThread.join(5000); // 等待最多5秒 + } catch (InterruptedException e) { + Log.w(TAG, "等待日志写入线程结束被中断"); + } + } + + // 处理队列中剩余的日志 + processRemainingLogs(); + + Log.i(TAG, "日志管理器已停止"); + } + + /** + * 记录调试日志 + */ + public static void logDebug(String tag, String message) { + if (instance != null) { + instance.addLogEntry("DEBUG", tag, message, null); + } + } + + /** + * 记录信息日志 + */ + public static void logInfo(String tag, String message) { + if (instance != null) { + instance.addLogEntry("INFO", tag, message, null); + } + } + + /** + * 记录警告日志 + */ + public static void logWarning(String tag, String message) { + if (instance != null) { + instance.addLogEntry("WARN", tag, message, null); + } + } + + /** + * 记录错误日志 + */ + public static void logError(String tag, String message) { + if (instance != null) { + instance.addLogEntry("ERROR", tag, message, null); + } + } + + /** + * 记录错误日志(带异常) + */ + public static void logError(String tag, String message, Throwable throwable) { + if (instance != null) { + instance.addLogEntry("ERROR", tag, message, throwable); + } + } + + /** + * 记录操作日志 + */ + public static void logOperation(String operation, String details) { + if (instance != null) { + instance.addLogEntry("OPERATION", "App", operation + ": " + details, null); + } + } + + /** + * 记录性能日志 + */ + public static void logPerformance(String operation, long duration) { + if (instance != null) { + String message = String.format("%s 耗时: %dms", operation, duration); + instance.addLogEntry("PERFORMANCE", "App", message, null); + } + } + + /** + * 添加日志条目到队列 + */ + private void addLogEntry(String level, String tag, String message, Throwable throwable) { + try { + LogEntry entry = new LogEntry(level, tag, message, throwable); + if (!logQueue.offer(entry)) { + Log.w(TAG, "日志队列已满,丢弃日志: " + message); + } + } catch (Exception e) { + Log.e(TAG, "添加日志条目失败", e); + } + } + + /** + * 运行日志写入器 + */ + private void runLogWriter() { + BufferedWriter writer = null; + + try { + while (isRunning || !logQueue.isEmpty()) { + try { + LogEntry entry = logQueue.take(); // 阻塞等待日志条目 + + // 检查是否需要轮转日志文件 + checkLogRotation(); + + // 打开或重新打开文件 + if (writer == null) { + writer = new BufferedWriter(new FileWriter(currentLogFile, true)); + } + + // 写入日志 + writeLogEntry(writer, entry); + + // 定期刷新缓冲区 + writer.flush(); + + } catch (InterruptedException e) { + if (!isRunning) { + break; + } + } catch (IOException e) { + Log.e(TAG, "写入日志失败", e); + + // 重新打开文件 + if (writer != null) { + try { + writer.close(); + } catch (IOException ignored) { + } + writer = null; + } + } + } + } finally { + if (writer != null) { + try { + writer.close(); + } catch (IOException e) { + Log.e(TAG, "关闭日志文件失败", e); + } + } + } + } + + /** + * 写入日志条目 + */ + private void writeLogEntry(BufferedWriter writer, LogEntry entry) throws IOException { + String timestamp = dateFormat.format(new Date(entry.timestamp)); + String logLine = String.format("[%s] %s/%s: %s%n", + timestamp, entry.level, entry.tag, entry.message); + + writer.write(logLine); + + // 如果有异常,写入堆栈信息 + if (entry.throwable != null) { + writer.write("Exception: " + entry.throwable.toString() + "\n"); + StackTraceElement[] stackTrace = entry.throwable.getStackTrace(); + for (StackTraceElement element : stackTrace) { + writer.write(" at " + element.toString() + "\n"); + } + } + } + + /** + * 检查日志轮转 + */ + private void checkLogRotation() { + if (currentLogFile.exists() && currentLogFile.length() > MAX_LOG_SIZE) { + rotateLogFile(); + } + } + + /** + * 轮转日志文件 + */ + private void rotateLogFile() { + try { + String timestamp = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss", Locale.getDefault()).format(new Date()); + String rotatedFileName = "oxface_operation_" + timestamp + ".log"; + File rotatedFile = new File(logDir, rotatedFileName); + + if (currentLogFile.renameTo(rotatedFile)) { + Log.i(TAG, "日志文件轮转成功: " + rotatedFileName); + + // 清理旧的日志文件 + cleanupOldLogFiles(); + } else { + Log.w(TAG, "日志文件轮转失败"); + } + } catch (Exception e) { + Log.e(TAG, "日志轮转失败", e); + } + } + + /** + * 清理旧的日志文件 + */ + private void cleanupOldLogFiles() { + try { + File[] logFiles = logDir.listFiles(); + if (logFiles == null || logFiles.length <= MAX_LOG_FILES) { + return; + } + + // 按修改时间排序 + java.util.Arrays.sort(logFiles, new java.util.Comparator() { + @Override + public int compare(File f1, File f2) { + return Long.compare(f1.lastModified(), f2.lastModified()); + } + }); + + // 删除最旧的文件(保留当前日志文件) + int filesToDelete = logFiles.length - MAX_LOG_FILES; + for (int i = 0; i < filesToDelete; i++) { + if (!logFiles[i].equals(currentLogFile) && logFiles[i].delete()) { + Log.d(TAG, "已删除旧日志文件: " + logFiles[i].getName()); + } + } + } catch (Exception e) { + Log.e(TAG, "清理旧日志文件失败", e); + } + } + + /** + * 处理队列中剩余的日志 + */ + private void processRemainingLogs() { + if (logQueue.isEmpty()) { + return; + } + + try (BufferedWriter writer = new BufferedWriter(new FileWriter(currentLogFile, true))) { + LogEntry entry; + while ((entry = logQueue.poll()) != null) { + writeLogEntry(writer, entry); + } + writer.flush(); + } catch (IOException e) { + Log.e(TAG, "处理剩余日志失败", e); + } + } + + /** + * 获取日志目录 + */ + public File getLogDirectory() { + return logDir; + } + + /** + * 获取当前日志文件 + */ + public File getCurrentLogFile() { + return currentLogFile; + } + + /** + * 获取日志文件大小 + */ + public long getLogFileSize() { + return currentLogFile.exists() ? currentLogFile.length() : 0; + } +} \ No newline at end of file diff --git a/app/src/main/java/com/ouxuan/oxface/utils/MaintenanceScheduler.java b/app/src/main/java/com/ouxuan/oxface/utils/MaintenanceScheduler.java new file mode 100644 index 0000000..20123f6 --- /dev/null +++ b/app/src/main/java/com/ouxuan/oxface/utils/MaintenanceScheduler.java @@ -0,0 +1,533 @@ +package com.ouxuan.oxface.utils; + +import android.content.Context; +import android.util.Log; + +import com.bumptech.glide.Glide; +import com.ouxuan.oxface.network.NetworkManager; +import com.ouxuan.oxface.network.NetworkStabilityManager; + +import java.util.Timer; +import java.util.TimerTask; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +/** + * 维护任务调度器 + * 用于24小时无人值守环境下的定时维护任务 + */ +public class MaintenanceScheduler { + + private static final String TAG = "MaintenanceScheduler"; + + // 维护间隔时间(毫秒) + private static final long LIGHT_MAINTENANCE_INTERVAL = 30 * 60 * 1000; // 30分钟 - 轻度维护 + private static final long MEDIUM_MAINTENANCE_INTERVAL = 2 * 60 * 60 * 1000; // 2小时 - 中度维护 + private static final long HEAVY_MAINTENANCE_INTERVAL = 6 * 60 * 60 * 1000; // 6小时 - 重度维护 + private static final long DAILY_MAINTENANCE_INTERVAL = 24 * 60 * 60 * 1000; // 24小时 - 每日维护 + + private static MaintenanceScheduler instance; + private Context context; + private ScheduledExecutorService scheduledExecutor; + private boolean isRunning = false; + + // 维护任务计数器 + private int lightMaintenanceCount = 0; + private int mediumMaintenanceCount = 0; + private int heavyMaintenanceCount = 0; + private int dailyMaintenanceCount = 0; + + private MaintenanceScheduler(Context context) { + this.context = context.getApplicationContext(); + this.scheduledExecutor = Executors.newScheduledThreadPool(2); + } + + public static synchronized MaintenanceScheduler getInstance(Context context) { + if (instance == null) { + instance = new MaintenanceScheduler(context); + } + return instance; + } + + /** + * 启动维护任务调度 + */ + public void startMaintenance() { + if (isRunning) { + Log.i(TAG, "维护调度器已在运行中"); + return; + } + + isRunning = true; + + // 调度轻度维护任务 - 每30分钟 + scheduledExecutor.scheduleAtFixedRate( + new Runnable() { + @Override + public void run() { + performLightMaintenance(); + } + }, + LIGHT_MAINTENANCE_INTERVAL, + LIGHT_MAINTENANCE_INTERVAL, + TimeUnit.MILLISECONDS + ); + + // 调度中度维护任务 - 每2小时 + scheduledExecutor.scheduleAtFixedRate( + new Runnable() { + @Override + public void run() { + performMediumMaintenance(); + } + }, + MEDIUM_MAINTENANCE_INTERVAL, + MEDIUM_MAINTENANCE_INTERVAL, + TimeUnit.MILLISECONDS + ); + + // 调度重度维护任务 - 每6小时 + scheduledExecutor.scheduleAtFixedRate( + new Runnable() { + @Override + public void run() { + performHeavyMaintenance(); + } + }, + HEAVY_MAINTENANCE_INTERVAL, + HEAVY_MAINTENANCE_INTERVAL, + TimeUnit.MILLISECONDS + ); + + // 调度每日维护任务 - 每24小时 + scheduledExecutor.scheduleAtFixedRate( + new Runnable() { + @Override + public void run() { + performDailyMaintenance(); + } + }, + DAILY_MAINTENANCE_INTERVAL, + DAILY_MAINTENANCE_INTERVAL, + TimeUnit.MILLISECONDS + ); + + Log.i(TAG, "维护任务调度器已启动"); + LogManager.logOperation("MaintenanceScheduler", "维护任务调度器启动"); + } + + /** + * 停止维护任务调度 + */ + public void stopMaintenance() { + if (!isRunning) { + return; + } + + isRunning = false; + + if (scheduledExecutor != null && !scheduledExecutor.isShutdown()) { + scheduledExecutor.shutdown(); + try { + if (!scheduledExecutor.awaitTermination(30, TimeUnit.SECONDS)) { + scheduledExecutor.shutdownNow(); + } + } catch (InterruptedException e) { + scheduledExecutor.shutdownNow(); + Thread.currentThread().interrupt(); + } + } + + Log.i(TAG, "维护任务调度器已停止"); + LogManager.logOperation("MaintenanceScheduler", "维护任务调度器停止"); + } + + /** + * 轻度维护任务 - 每30分钟执行 + */ + private void performLightMaintenance() { + try { + lightMaintenanceCount++; + Log.d(TAG, "开始轻度维护任务 #" + lightMaintenanceCount); + + long startTime = System.currentTimeMillis(); + + // 检查内存状态 + checkMemoryStatus(); + + // 检查网络状态 + checkNetworkStatus(); + + // 轻量级垃圾回收建议 + System.gc(); + + long duration = System.currentTimeMillis() - startTime; + Log.d(TAG, "轻度维护任务完成,耗时: " + duration + "ms"); + LogManager.logPerformance("轻度维护任务", duration); + + } catch (Exception e) { + Log.e(TAG, "轻度维护任务失败", e); + LogManager.logError(TAG, "轻度维护任务失败", e); + } + } + + /** + * 中度维护任务 - 每2小时执行 + */ + private void performMediumMaintenance() { + try { + mediumMaintenanceCount++; + Log.i(TAG, "开始中度维护任务 #" + mediumMaintenanceCount); + + long startTime = System.currentTimeMillis(); + + // 执行内存清理 + performMemoryCleanup(); + + // 检查应用保持活跃状态 + checkKeepAliveStatus(); + + // 执行网络连接重置 + resetNetworkConnections(); + + // 更强力的垃圾回收 + for (int i = 0; i < 3; i++) { + System.gc(); + try { + Thread.sleep(100); + } catch (InterruptedException e) { + break; + } + } + + long duration = System.currentTimeMillis() - startTime; + Log.i(TAG, "中度维护任务完成,耗时: " + duration + "ms"); + LogManager.logPerformance("中度维护任务", duration); + + } catch (Exception e) { + Log.e(TAG, "中度维护任务失败", e); + LogManager.logError(TAG, "中度维护任务失败", e); + } + } + + /** + * 重度维护任务 - 每6小时执行 + */ + private void performHeavyMaintenance() { + try { + heavyMaintenanceCount++; + Log.w(TAG, "开始重度维护任务 #" + heavyMaintenanceCount); + + long startTime = System.currentTimeMillis(); + + // 执行深度内存清理 + performDeepMemoryCleanup(); + + // 清理磁盘缓存 + clearDiskCaches(); + + // 重新初始化网络管理器 + reinitializeNetworkManager(); + + // 执行健康检查 + performSystemHealthCheck(); + + // 清理日志文件 + cleanupLogFiles(); + + long duration = System.currentTimeMillis() - startTime; + Log.w(TAG, "重度维护任务完成,耗时: " + duration + "ms"); + LogManager.logPerformance("重度维护任务", duration); + + } catch (Exception e) { + Log.e(TAG, "重度维护任务失败", e); + LogManager.logError(TAG, "重度维护任务失败", e); + } + } + + /** + * 每日维护任务 - 每24小时执行 + */ + private void performDailyMaintenance() { + try { + dailyMaintenanceCount++; + Log.w(TAG, "开始每日维护任务 #" + dailyMaintenanceCount); + + long startTime = System.currentTimeMillis(); + + // 生成系统运行报告 + generateSystemReport(); + + // 执行全面系统清理 + performComprehensiveCleanup(); + + // 重置所有计数器和统计数据 + resetCounters(); + + // 验证系统完整性 + validateSystemIntegrity(); + + long duration = System.currentTimeMillis() - startTime; + Log.w(TAG, "每日维护任务完成,耗时: " + duration + "ms"); + LogManager.logPerformance("每日维护任务", duration); + LogManager.logOperation("MaintenanceScheduler", "完成第" + dailyMaintenanceCount + "次每日维护"); + + } catch (Exception e) { + Log.e(TAG, "每日维护任务失败", e); + LogManager.logError(TAG, "每日维护任务失败", e); + } + } + + /** + * 检查内存状态 + */ + private void checkMemoryStatus() { + MemoryManager memoryManager = MemoryManager.getInstance(context); + float memoryUsage = memoryManager.getCurrentMemoryUsage(); + + if (memoryUsage > 0.80f) { + Log.w(TAG, "内存使用率较高: " + String.format("%.1f%%", memoryUsage * 100)); + memoryManager.performMemoryCleanup(); + } + } + + /** + * 检查网络状态 + */ + private void checkNetworkStatus() { + NetworkStabilityManager networkManager = NetworkStabilityManager.getInstance(context); + boolean networkAvailable = networkManager.isNetworkAvailable(); + + if (!networkAvailable) { + Log.w(TAG, "网络连接不可用"); + LogManager.logWarning(TAG, "维护检查发现网络连接不可用"); + } + } + + /** + * 执行内存清理 + */ + private void performMemoryCleanup() { + MemoryManager memoryManager = MemoryManager.getInstance(context); + memoryManager.performMemoryCleanup(); + + // 清理Glide缓存 + Glide.get(context).clearMemory(); + + Log.d(TAG, "内存清理完成"); + } + + /** + * 检查保持活跃状态 + */ + private void checkKeepAliveStatus() { + KeepAliveManager keepAliveManager = KeepAliveManager.getInstance(context); + boolean isKeepingAlive = keepAliveManager.isKeepingAlive(); + + if (!isKeepingAlive) { + Log.w(TAG, "保持活跃功能未启用"); + LogManager.logWarning(TAG, "维护检查发现保持活跃功能未启用"); + } + + // 记录电源状态 + keepAliveManager.logPowerStatus(); + } + + /** + * 重置网络连接 + */ + private void resetNetworkConnections() { + try { + // 这里可以添加重置网络连接的逻辑 + // 例如重新初始化HTTP客户端等 + Log.d(TAG, "网络连接重置完成"); + } catch (Exception e) { + Log.e(TAG, "重置网络连接失败", e); + } + } + + /** + * 执行深度内存清理 + */ + private void performDeepMemoryCleanup() { + MemoryManager memoryManager = MemoryManager.getInstance(context); + + // 多次执行内存清理 + for (int i = 0; i < 3; i++) { + memoryManager.performMemoryCleanup(); + try { + Thread.sleep(200); + } catch (InterruptedException e) { + break; + } + } + + Log.i(TAG, "深度内存清理完成"); + } + + /** + * 清理磁盘缓存 + */ + private void clearDiskCaches() { + // 在后台线程中清理磁盘缓存 + new Thread(new Runnable() { + @Override + public void run() { + try { + Glide.get(context).clearDiskCache(); + Log.i(TAG, "磁盘缓存清理完成"); + } catch (Exception e) { + Log.e(TAG, "磁盘缓存清理失败", e); + } + } + }).start(); + } + + /** + * 重新初始化网络管理器 + */ + private void reinitializeNetworkManager() { + try { + NetworkManager networkManager = NetworkManager.getInstance(); + // 这里可以添加重新初始化网络管理器的逻辑 + Log.i(TAG, "网络管理器重新初始化完成"); + } catch (Exception e) { + Log.e(TAG, "重新初始化网络管理器失败", e); + } + } + + /** + * 执行系统健康检查 + */ + private void performSystemHealthCheck() { + HealthMonitor healthMonitor = HealthMonitor.getInstance(context); + healthMonitor.performHealthCheck(); + + HealthMonitor.HealthReport report = healthMonitor.getCurrentHealthReport(); + Log.i(TAG, "系统健康检查完成,状态: " + report.overallStatus); + } + + /** + * 清理日志文件 + */ + private void cleanupLogFiles() { + try { + // LogManager会自动处理日志轮转和清理 + LogManager logManager = LogManager.getInstance(context); + Log.d(TAG, "日志文件清理检查完成"); + } catch (Exception e) { + Log.e(TAG, "日志文件清理失败", e); + } + } + + /** + * 生成系统运行报告 + */ + private void generateSystemReport() { + try { + HealthMonitor healthMonitor = HealthMonitor.getInstance(context); + HealthMonitor.HealthReport report = healthMonitor.getCurrentHealthReport(); + + String reportMessage = String.format( + "系统运行报告 - 运行时间: %d小时, 内存使用: %.1f%%, 网络: %s, 维护次数: L%d/M%d/H%d/D%d", + report.uptime / (1000 * 60 * 60), + report.memoryUsage * 100, + report.networkAvailable ? "正常" : "异常", + lightMaintenanceCount, + mediumMaintenanceCount, + heavyMaintenanceCount, + dailyMaintenanceCount + ); + + Log.i(TAG, reportMessage); + LogManager.logOperation("SystemReport", reportMessage); + + } catch (Exception e) { + Log.e(TAG, "生成系统报告失败", e); + } + } + + /** + * 执行全面系统清理 + */ + private void performComprehensiveCleanup() { + // 执行所有级别的清理任务 + performDeepMemoryCleanup(); + clearDiskCaches(); + + // 等待一段时间让清理任务完成 + try { + Thread.sleep(2000); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + + Log.i(TAG, "全面系统清理完成"); + } + + /** + * 重置计数器 + */ + private void resetCounters() { + lightMaintenanceCount = 0; + mediumMaintenanceCount = 0; + heavyMaintenanceCount = 0; + // 不重置每日维护计数器,用于跟踪总运行天数 + + Log.d(TAG, "维护任务计数器已重置"); + } + + /** + * 验证系统完整性 + */ + private void validateSystemIntegrity() { + try { + // 检查关键组件是否正常运行 + boolean memoryManagerOk = MemoryManager.getInstance(context).isMemoryHealthy(); + boolean networkManagerOk = NetworkStabilityManager.getInstance(context).isNetworkAvailable(); + boolean keepAliveOk = KeepAliveManager.getInstance(context).isKeepingAlive(); + + String integrityReport = String.format( + "系统完整性检查 - 内存管理: %s, 网络管理: %s, 保持活跃: %s", + memoryManagerOk ? "正常" : "异常", + networkManagerOk ? "正常" : "异常", + keepAliveOk ? "正常" : "异常" + ); + + Log.i(TAG, integrityReport); + LogManager.logOperation("SystemIntegrity", integrityReport); + + } catch (Exception e) { + Log.e(TAG, "系统完整性验证失败", e); + LogManager.logError(TAG, "系统完整性验证失败", e); + } + } + + /** + * 获取维护统计信息 + */ + public String getMaintenanceStats() { + return String.format( + "维护统计 - 轻度: %d次, 中度: %d次, 重度: %d次, 每日: %d次", + lightMaintenanceCount, + mediumMaintenanceCount, + heavyMaintenanceCount, + dailyMaintenanceCount + ); + } + + /** + * 立即执行维护任务 + */ + public void performImmediateMaintenance() { + Log.i(TAG, "立即执行维护任务"); + + new Thread(new Runnable() { + @Override + public void run() { + performMediumMaintenance(); + } + }).start(); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/ouxuan/oxface/utils/MemoryManager.java b/app/src/main/java/com/ouxuan/oxface/utils/MemoryManager.java new file mode 100644 index 0000000..9b710a6 --- /dev/null +++ b/app/src/main/java/com/ouxuan/oxface/utils/MemoryManager.java @@ -0,0 +1,245 @@ +package com.ouxuan.oxface.utils; + +import android.app.ActivityManager; +import android.content.Context; +import android.util.Log; + +import com.bumptech.glide.Glide; + +/** + * 内存管理器 + * 用于24小时无人值守环境下的内存监控和优化 + */ +public class MemoryManager { + + private static final String TAG = "MemoryManager"; + private static final float MEMORY_THRESHOLD = 0.85f; // 85%内存使用率阈值 + private static final float CRITICAL_MEMORY_THRESHOLD = 0.95f; // 95%临界阈值 + private static final long MEMORY_CHECK_INTERVAL = 30 * 1000; // 30秒检查间隔 + + private static MemoryManager instance; + private Context context; + private boolean isMonitoring = false; + + private MemoryManager(Context context) { + this.context = context.getApplicationContext(); + } + + public static synchronized MemoryManager getInstance(Context context) { + if (instance == null) { + instance = new MemoryManager(context); + } + return instance; + } + + /** + * 开始内存监控 + */ + public void startMemoryMonitoring() { + if (isMonitoring) { + return; + } + + isMonitoring = true; + Log.i(TAG, "开始内存监控"); + + Thread monitorThread = new Thread(new Runnable() { + @Override + public void run() { + while (isMonitoring) { + try { + monitorMemory(); + Thread.sleep(MEMORY_CHECK_INTERVAL); + } catch (InterruptedException e) { + Log.w(TAG, "内存监控线程被中断"); + break; + } catch (Exception e) { + Log.e(TAG, "内存监控异常", e); + } + } + } + }); + monitorThread.setName("MemoryMonitor"); + monitorThread.setDaemon(true); + monitorThread.start(); + } + + /** + * 停止内存监控 + */ + public void stopMemoryMonitoring() { + isMonitoring = false; + Log.i(TAG, "停止内存监控"); + } + + /** + * 监控内存使用情况 + */ + public void monitorMemory() { + try { + Runtime runtime = Runtime.getRuntime(); + long maxMemory = runtime.maxMemory(); + long totalMemory = runtime.totalMemory(); + long freeMemory = runtime.freeMemory(); + long usedMemory = totalMemory - freeMemory; + float memoryUsage = (float) usedMemory / maxMemory; + + // 记录详细内存信息 + Log.d(TAG, String.format("内存使用情况 - 使用率: %.1f%%, 已用: %dMB, 最大: %dMB", + memoryUsage * 100, usedMemory / (1024 * 1024), maxMemory / (1024 * 1024))); + + // 检查内存使用率 + if (memoryUsage > CRITICAL_MEMORY_THRESHOLD) { + // 临界状态,强制清理 + Log.w(TAG, "内存使用率达到临界状态: " + String.format("%.1f%%", memoryUsage * 100)); + performCriticalMemoryCleanup(); + } else if (memoryUsage > MEMORY_THRESHOLD) { + // 超过阈值,执行清理 + Log.w(TAG, "内存使用率过高: " + String.format("%.1f%%", memoryUsage * 100)); + performMemoryCleanup(); + } + + // 检查系统内存情况 + checkSystemMemory(); + + } catch (Exception e) { + Log.e(TAG, "内存监控失败", e); + } + } + + /** + * 执行内存清理 + */ + public void performMemoryCleanup() { + try { + Log.i(TAG, "开始内存清理"); + + // 清理Glide图片缓存 + if (context != null) { + Glide.get(context).clearMemory(); + Log.d(TAG, "已清理Glide内存缓存"); + } + + // 建议垃圾回收 + System.gc(); + Log.d(TAG, "已触发垃圾回收"); + + // 记录清理后的内存状态 + logMemoryStatus("清理后"); + + } catch (Exception e) { + Log.e(TAG, "内存清理失败", e); + } + } + + /** + * 执行临界内存清理 + */ + private void performCriticalMemoryCleanup() { + try { + Log.w(TAG, "执行临界内存清理"); + + // 清理所有可能的缓存 + if (context != null) { + Glide.get(context).clearMemory(); + // 强制清理磁盘缓存(在后台线程中) + new Thread(new Runnable() { + @Override + public void run() { + Glide.get(context).clearDiskCache(); + } + }).start(); + } + + // 多次触发垃圾回收 + for (int i = 0; i < 3; i++) { + System.gc(); + try { + Thread.sleep(100); + } catch (InterruptedException e) { + break; + } + } + + Log.w(TAG, "临界内存清理完成"); + + } catch (Exception e) { + Log.e(TAG, "临界内存清理失败", e); + } + } + + /** + * 检查系统内存情况 + */ + private void checkSystemMemory() { + try { + ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); + if (activityManager != null) { + ActivityManager.MemoryInfo memoryInfo = new ActivityManager.MemoryInfo(); + activityManager.getMemoryInfo(memoryInfo); + + float availableMemoryPercentage = (float) memoryInfo.availMem / memoryInfo.totalMem; + + Log.d(TAG, String.format("系统内存 - 可用: %dMB, 总计: %dMB, 可用率: %.1f%%", + memoryInfo.availMem / (1024 * 1024), + memoryInfo.totalMem / (1024 * 1024), + availableMemoryPercentage * 100)); + + // 如果系统内存不足,记录警告 + if (memoryInfo.lowMemory) { + Log.w(TAG, "系统内存不足警告"); + } + } + } catch (Exception e) { + Log.e(TAG, "检查系统内存失败", e); + } + } + + /** + * 记录内存状态 + */ + private void logMemoryStatus(String prefix) { + try { + Runtime runtime = Runtime.getRuntime(); + long maxMemory = runtime.maxMemory(); + long totalMemory = runtime.totalMemory(); + long freeMemory = runtime.freeMemory(); + long usedMemory = totalMemory - freeMemory; + float memoryUsage = (float) usedMemory / maxMemory; + + Log.i(TAG, String.format("%s内存状态 - 使用率: %.1f%%, 已用: %dMB, 空闲: %dMB, 最大: %dMB", + prefix, + memoryUsage * 100, + usedMemory / (1024 * 1024), + freeMemory / (1024 * 1024), + maxMemory / (1024 * 1024))); + + } catch (Exception e) { + Log.e(TAG, "记录内存状态失败", e); + } + } + + /** + * 获取当前内存使用率 + */ + public float getCurrentMemoryUsage() { + try { + Runtime runtime = Runtime.getRuntime(); + long maxMemory = runtime.maxMemory(); + long totalMemory = runtime.totalMemory(); + long freeMemory = runtime.freeMemory(); + long usedMemory = totalMemory - freeMemory; + return (float) usedMemory / maxMemory; + } catch (Exception e) { + Log.e(TAG, "获取内存使用率失败", e); + return 0f; + } + } + + /** + * 检查内存是否健康 + */ + public boolean isMemoryHealthy() { + return getCurrentMemoryUsage() < MEMORY_THRESHOLD; + } +} \ No newline at end of file diff --git a/app/src/main/java/com/ouxuan/oxface/utils/UtilCodeHelper.java b/app/src/main/java/com/ouxuan/oxface/utils/UtilCodeHelper.java new file mode 100644 index 0000000..a236734 --- /dev/null +++ b/app/src/main/java/com/ouxuan/oxface/utils/UtilCodeHelper.java @@ -0,0 +1,382 @@ +package com.ouxuan.oxface.utils; + +import android.content.Context; + +import com.blankj.utilcode.util.AppUtils; +import com.blankj.utilcode.util.DeviceUtils; +import com.blankj.utilcode.util.FileUtils; +import com.blankj.utilcode.util.NetworkUtils; +import com.blankj.utilcode.util.PathUtils; +import com.blankj.utilcode.util.PhoneUtils; +import com.blankj.utilcode.util.ScreenUtils; +import com.blankj.utilcode.util.TimeUtils; +import com.blankj.utilcode.util.ToastUtils; + +/** + * UtilCode工具库使用示例类 + * 提供常用的Android开发工具方法封装 + */ +public class UtilCodeHelper { + + private static final String TAG = "UtilCodeHelper"; + + /** + * 应用信息相关工具方法 + */ + public static class App { + /** + * 获取应用版本名称 + */ + public static String getAppVersionName() { + return AppUtils.getAppVersionName(); + } + + /** + * 获取应用版本号 + */ + public static int getAppVersionCode() { + return AppUtils.getAppVersionCode(); + } + + /** + * 获取应用包名 + */ + public static String getAppPackageName() { + return AppUtils.getAppPackageName(); + } + + /** + * 判断应用是否在前台 + */ + public static boolean isAppForeground() { + return AppUtils.isAppForeground(); + } + + /** + * 获取应用信息摘要 + */ + public static String getAppInfoSummary() { + return String.format("应用信息 - 包名: %s, 版本: %s(%d)", + getAppPackageName(), getAppVersionName(), getAppVersionCode()); + } + } + + /** + * 设备信息相关工具方法 + */ + public static class Device { + /** + * 获取设备型号 + */ + public static String getModel() { + return DeviceUtils.getModel(); + } + + /** + * 获取设备制造商 + */ + public static String getManufacturer() { + return DeviceUtils.getManufacturer(); + } + + /** + * 获取Android版本 + */ + public static String getSDKVersionName() { + return DeviceUtils.getSDKVersionName(); + } + + /** + * 获取Android API级别 + */ + public static int getSDKVersionCode() { + return DeviceUtils.getSDKVersionCode(); + } + + /** + * 判断设备是否为平板 + */ + public static boolean isTablet() { + return DeviceUtils.isTablet(); + } + + /** + * 获取设备信息摘要 + */ + public static String getDeviceInfoSummary() { + return String.format("设备信息 - 型号: %s, 制造商: %s, Android: %s(API %d), 平板: %s", + getModel(), getManufacturer(), getSDKVersionName(), + getSDKVersionCode(), isTablet() ? "是" : "否"); + } + } + + /** + * 屏幕信息相关工具方法 + */ + public static class Screen { + /** + * 获取屏幕宽度(像素) + */ + public static int getScreenWidth() { + return ScreenUtils.getScreenWidth(); + } + + /** + * 获取屏幕高度(像素) + */ + public static int getScreenHeight() { + return ScreenUtils.getScreenHeight(); + } + + /** + * 获取屏幕密度 + */ + public static float getScreenDensity() { + return ScreenUtils.getScreenDensity(); + } + + /** + * dp转px + */ + public static int dp2px(float dpValue) { + return com.blankj.utilcode.util.SizeUtils.dp2px(dpValue); + } + + /** + * px转dp + */ + public static int px2dp(float pxValue) { + return com.blankj.utilcode.util.SizeUtils.px2dp(pxValue); + } + + /** + * 获取屏幕信息摘要 + */ + public static String getScreenInfoSummary() { + return String.format("屏幕信息 - 尺寸: %dx%d, 密度: %.2f", + getScreenWidth(), getScreenHeight(), getScreenDensity()); + } + } + + /** + * 网络相关工具方法 + */ + public static class Network { + /** + * 判断网络是否连接 + */ + public static boolean isConnected() { + return NetworkUtils.isConnected(); + } + + /** + * 判断是否为WiFi连接 + */ + public static boolean isWifiConnected() { + return NetworkUtils.isWifiConnected(); + } + + /** + * 判断是否为移动数据连接 + */ + public static boolean isMobileData() { + return NetworkUtils.isMobileData(); + } + + /** + * 获取网络类型 + */ + public static NetworkUtils.NetworkType getNetworkType() { + return NetworkUtils.getNetworkType(); + } + + /** + * 获取网络状态摘要 + */ + public static String getNetworkStatusSummary() { + if (!isConnected()) { + return "网络状态 - 未连接"; + } + + String connectionType = "未知"; + if (isWifiConnected()) { + connectionType = "WiFi"; + } else if (isMobileData()) { + connectionType = "移动数据"; + } + + return String.format("网络状态 - 已连接(%s), 类型: %s", + connectionType, getNetworkType()); + } + } + + /** + * 文件操作相关工具方法 + */ + public static class File { + /** + * 获取应用外部存储目录 + */ + public static String getAppExternalPath() { + return PathUtils.getExternalAppDataPath(); + } + + /** + * 获取应用内部存储目录 + */ + public static String getAppInternalPath() { + return PathUtils.getInternalAppDataPath(); + } + + /** + * 创建目录 + */ + public static boolean createDir(String dirPath) { + return FileUtils.createOrExistsDir(dirPath); + } + + /** + * 判断文件是否存在 + */ + public static boolean isFileExists(String filePath) { + return FileUtils.isFileExists(filePath); + } + + /** + * 获取文件大小(字节) + */ + public static long getFileSize(String filePath) { + return FileUtils.getFileLength(filePath); + } + + /** + * 删除文件或目录 + */ + public static boolean delete(String path) { + return FileUtils.delete(path); + } + } + + /** + * 时间相关工具方法 + */ + public static class Time { + /** + * 获取当前时间戳(毫秒) + */ + public static long getCurrentTimeMillis() { + return System.currentTimeMillis(); + } + + /** + * 时间戳转字符串(默认格式: yyyy-MM-dd HH:mm:ss) + */ + public static String millis2String(long millis) { + return TimeUtils.millis2String(millis); + } + + /** + * 时间戳转字符串(自定义格式) + */ + public static String millis2String(long millis, String pattern) { + return TimeUtils.millis2String(millis, pattern); + } + + /** + * 字符串转时间戳 + */ + public static long string2Millis(String time, String pattern) { + return TimeUtils.string2Millis(time, pattern); + } + + /** + * 获取友好的时间描述 + */ + public static String getFriendlyTimeSpanByNow(long millis) { + return TimeUtils.getFriendlyTimeSpanByNow(millis); + } + } + + /** + * Toast相关工具方法 + */ + public static class Toast { + /** + * 显示短时间Toast + */ + public static void showShort(String message) { + ToastUtils.showShort(message); + } + + /** + * 显示长时间Toast + */ + public static void showLong(String message) { + ToastUtils.showLong(message); + } + + /** + * 取消Toast显示 + */ + public static void cancel() { + ToastUtils.cancel(); + } + } + + /** + * 手机相关工具方法 + */ + public static class Phone { + /** + * 判断设备是否为手机 + */ + public static boolean isPhone() { + return PhoneUtils.isPhone(); + } + + /** + * 获取IMEI(需要权限) + */ + public static String getIMEI() { + try { + return PhoneUtils.getIMEI(); + } catch (Exception e) { + LogManager.logWarning(TAG, "获取IMEI失败: " + e.getMessage()); + return ""; + } + } + + /** + * 获取手机型号 + */ + public static String getPhoneType() { + return PhoneUtils.getPhoneType() + ""; + } + } + + /** + * 系统信息汇总 + * 用于24小时无人值守应用的系统状态记录 + */ + public static String getSystemInfoSummary() { + StringBuilder summary = new StringBuilder(); + summary.append("=== 系统信息汇总 ===\n"); + summary.append(App.getAppInfoSummary()).append("\n"); + summary.append(Device.getDeviceInfoSummary()).append("\n"); + summary.append(Screen.getScreenInfoSummary()).append("\n"); + summary.append(Network.getNetworkStatusSummary()).append("\n"); + summary.append("当前时间: ").append(Time.millis2String(Time.getCurrentTimeMillis())).append("\n"); + summary.append("应用前台状态: ").append(App.isAppForeground() ? "是" : "否").append("\n"); + summary.append("=================="); + + return summary.toString(); + } + + /** + * 记录系统信息到日志 + */ + public static void logSystemInfo() { + String systemInfo = getSystemInfoSummary(); + LogManager.logOperation(TAG, systemInfo); + } +} \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index 35efae4..8e2e39b 100644 --- a/gradle.properties +++ b/gradle.properties @@ -25,4 +25,20 @@ android.nonTransitiveRClass=true # Disable offline mode for build org.gradle.offline=false # Android SDK path -android.sdk.path=/Users/zmt/Library/Android/sdk \ No newline at end of file +android.sdk.path=/Users/zmt/Library/Android/sdk + +# 24小时运行优化配置 +# 增大Gradle内存分配 +org.gradle.jvmargs=-Xmx4096m -Dfile.encoding=UTF-8 +# 并行构建优化 +org.gradle.parallel=true +# 启用守护进程 +org.gradle.daemon=true +# 配置缓存 +org.gradle.caching=true + +# Java版本兼容性配置 +# 抑制不兼容警告 +android.javaCompile.suppressSourceTargetDeprecationWarning=true +# 启用R8优化 +android.enableR8.fullMode=false \ No newline at end of file