# 轻应用生命周期 本文档详细介绍阑山桌面轻应用的生命周期、加载流程和各个阶段的职责。 ## 生命周期概览 轻应用从加载到卸载经历以下阶段: ``` ┌─────────────────────────────────────────────────────────┐ │ 轻应用生命周期 │ └─────────────────────────────────────────────────────────┘ 1. 发现 (Discovery) ├─ 扫描轻应用目录 ├─ 读取 airapp.json └─ 验证基本信息 ↓ 2. 加载 (Load) ├─ 创建 AirAppLoadContext ├─ 加载程序集 ├─ 解析依赖关系 └─ 验证兼容性 ↓ 3. 实例化 (Instantiate) ├─ 反射查找 IAirApp 实现 ├─ 创建轻应用实例 └─ 注入依赖 ↓ 4. 初始化 (Initialize) ├─ 调用 InitializeAsync() ├─ 注册组件 ├─ 注册设置页 ├─ 注册服务 └─ 订阅事件 ↓ 5. 运行中 (Running) ├─ 组件渲染和更新 ├─ 处理用户交互 ├─ 响应事件 └─ 执行后台任务 ↓ 6. 关闭 (Shutdown) ├─ 调用 ShutdownAsync() ├─ 保存状态 ├─ 取消订阅 ├─ 清理资源 └─ 卸载程序集 ``` ## 详细阶段说明 ### 1. 发现阶段 (Discovery) **时机**: 宿主启动时 **职责**: 扫描和识别轻应用 **流程**: ```csharp // AirAppDiscoveryService.cs (宿主代码) public List DiscoverAirApps() { var pluginsDir = Path.Combine( AppDataPath, "plugins" ); var descriptors = new List(); // 1. 扫描轻应用目录 foreach (var dir in Directory.GetDirectories(pluginsDir)) { var manifestPath = Path.Combine(dir, "airapp.json"); // 2. 读取 airapp.json if (!File.Exists(manifestPath)) { _logger.LogWarning($"AirApp manifest not found: {dir}"); continue; } try { var json = File.ReadAllText(manifestPath); var manifest = JsonSerializer.Deserialize(json); // 3. 验证基本信息 if (string.IsNullOrEmpty(manifest?.Id)) { _logger.LogWarning($"Invalid plugin manifest: {dir}"); continue; } descriptors.Add(new AirAppDescriptor { Id = manifest.Id, Name = manifest.Name, Version = manifest.Version, Directory = dir, Manifest = manifest }); } catch (Exception ex) { _logger.LogError(ex, $"Failed to read plugin manifest: {dir}"); } } return descriptors; } ``` **开发者注意事项**: - ✅ 确保 `airapp.json` 存在且格式正确 - ✅ 确保轻应用 ID 唯一 - ✅ 确保版本号符合语义化版本规范 ### 2. 加载阶段 (Load) **时机**: 发现轻应用后 **职责**: 加载轻应用程序集 **流程**: ```csharp // AirAppLoader.cs (宿主代码) public AirAppLoadResult LoadAirApp(AirAppDescriptor descriptor) { try { // 1. 创建隔离的加载上下文 var loadContext = new AirAppLoadContext(descriptor.Directory); // 2. 查找主程序集 var assemblyPath = Path.Combine( descriptor.Directory, $"{descriptor.Id}.dll" ); if (!File.Exists(assemblyPath)) { return AirAppLoadResult.Failed( $"AirApp assembly not found: {assemblyPath}" ); } // 3. 加载程序集 var assembly = loadContext.LoadFromAssemblyPath(assemblyPath); // 4. 验证依赖 if (!ValidateDependencies(descriptor.Manifest.Dependencies)) { return AirAppLoadResult.Failed("Dependency validation failed"); } // 5. 验证宿主版本兼容性 if (!IsHostVersionCompatible(descriptor.Manifest.MinHostVersion)) { return AirAppLoadResult.Failed( $"Incompatible host version. Required: {descriptor.Manifest.MinHostVersion}" ); } return AirAppLoadResult.Success(assembly, loadContext); } catch (Exception ex) { _logger.LogError(ex, $"Failed to load plugin: {descriptor.Id}"); return AirAppLoadResult.Failed(ex.Message); } } ``` **依赖解析**: ```json // airapp.json { "Dependencies": [ { "AirAppId": "com.example.anotherplugin", "MinVersion": "1.0.0" } ] } ``` **开发者注意事项**: - ✅ 主程序集名称应与轻应用 ID 匹配(或在清单中指定) - ✅ 所有依赖的 DLL 应在轻应用目录中 - ✅ 声明对其他轻应用的依赖关系 ### 3. 实例化阶段 (Instantiate) **时机**: 程序集加载后 **职责**: 创建轻应用实例 **流程**: ```csharp // AirAppActivator.cs (宿主代码) public IAirApp? CreateAirAppInstance(Assembly assembly) { try { // 1. 查找 IAirApp 实现类 var pluginType = assembly.GetTypes() .FirstOrDefault(t => typeof(IAirApp).IsAssignableFrom(t) && !t.IsAbstract && !t.IsInterface ); if (pluginType == null) { _logger.LogError("No IAirApp implementation found"); return null; } // 2. 创建实例 var plugin = Activator.CreateInstance(pluginType) as IAirApp; if (plugin == null) { _logger.LogError("Failed to create plugin instance"); return null; } return plugin; } catch (Exception ex) { _logger.LogError(ex, "Failed to instantiate plugin"); return null; } } ``` **开发者注意事项**: - ✅ 轻应用类必须有公共无参构造函数 - ✅ 一个轻应用程序集只能有一个 IAirApp 实现 - ✅ 不要在构造函数中执行耗时操作 ### 4. 初始化阶段 (Initialize) **时机**: 轻应用实例创建后 **职责**: 注册组件、服务和事件 **轻应用代码示例**: ```csharp public class MyAirApp : IAirApp { public async Task InitializeAsync(IAirAppRuntimeContext context) { // 1. 记录日志 context.Logger.LogInformation($"{Name} is initializing..."); // 2. 注册组件 var componentRegistry = context.Services .GetService(); if (componentRegistry != null) { // 注册多个组件 componentRegistry.RegisterComponent(); componentRegistry.RegisterComponent(); context.Logger.LogInformation("Components registered"); } // 3. 注册设置页 var settingsRegistry = context.Services .GetService(); if (settingsRegistry != null) { settingsRegistry.RegisterPage( title: "我的轻应用", category: "轻应用" ); context.Logger.LogInformation("Settings page registered"); } // 4. 注册公共 IPC 服务(如果需要) var ipcBuilder = context.Services .GetService(); if (ipcBuilder != null) { ipcBuilder.AddService( objectId: "default", notifyIds: new[] { "myplugin.event.changed" } ); } // 5. 订阅宿主事件 var eventBus = context.Services .GetService(); if (eventBus != null) { eventBus.Subscribe(OnThemeChanged); } // 6. 初始化后台服务(如果有) await InitializeBackgroundServicesAsync(context); context.Logger.LogInformation($"{Name} initialized successfully"); } private void OnThemeChanged(ThemeChangedEvent evt) { // 响应主题变更 } private async Task InitializeBackgroundServicesAsync(IAirAppRuntimeContext context) { // 启动定时任务等 await Task.CompletedTask; } } ``` **初始化最佳实践**: ```csharp public async Task InitializeAsync(IAirAppRuntimeContext context) { try { // ✅ 使用 try-catch 捕获异常 // ✅ 记录详细的日志 // ✅ 验证服务是否可用 // ✅ 使用 async/await 处理异步操作 // ❌ 不要阻塞 UI 线程 // ❌ 不要执行超过 5 秒的操作 _context = context; // 快速初始化 RegisterComponents(context); RegisterSettings(context); // 耗时操作使用后台任务 _ = Task.Run(async () => { await LoadDataAsync(); }); } catch (Exception ex) { context.Logger.LogError(ex, "AirApp initialization failed"); throw; // 让宿主知道初始化失败 } } ``` **开发者注意事项**: - ✅ InitializeAsync 应尽快完成(< 5 秒) - ✅ 耗时操作放在后台线程 - ✅ 妥善处理异常 - ✅ 保存 IAirAppRuntimeContext 引用供后续使用 - ❌ 不要在此阶段访问其他轻应用的服务(可能还未加载) ### 5. 运行中阶段 (Running) **时机**: 初始化完成后 **职责**: 响应用户交互和系统事件 **组件更新循环**: ```csharp // 宿主会定时调用组件的 UpdateAsync() public class MyComponent : ComponentBase { private HttpClient _httpClient; private DateTime _lastUpdate; public override async Task UpdateAsync() { // 定时更新数据(默认 1 秒调用一次) if (DateTime.Now - _lastUpdate > TimeSpan.FromMinutes(5)) { await FetchDataAsync(); _lastUpdate = DateTime.Now; } } private async Task FetchDataAsync() { try { var data = await _httpClient.GetStringAsync("https://api.example.com/data"); // 更新组件属性 Data = ParseData(data); } catch (Exception ex) { Logger.LogError(ex, "Failed to fetch data"); } } } ``` **事件响应**: ```csharp public class MyAirApp : IAirApp { public async Task InitializeAsync(IAirAppRuntimeContext context) { // 订阅系统事件 var eventBus = context.Services.GetService(); eventBus?.Subscribe(OnThemeChanged); eventBus?.Subscribe(OnLanguageChanged); eventBus?.Subscribe(OnSettingChanged); } private void OnThemeChanged(ThemeChangedEvent evt) { _logger.LogInformation($"Theme changed to: {evt.NewTheme}"); // 更新组件外观 } private void OnLanguageChanged(LanguageChangedEvent evt) { _logger.LogInformation($"Language changed to: {evt.NewLanguage}"); // 重新加载本地化资源 } private void OnSettingChanged(SettingChangedEvent evt) { if (evt.Key.StartsWith("MyAirApp.")) { // 响应轻应用设置变更 } } } ``` **开发者注意事项**: - ✅ 组件更新应快速完成 - ✅ 使用缓存避免重复计算 - ✅ 异步操作使用 async/await - ✅ 妥善处理网络错误 - ❌ 不要在 UpdateAsync 中执行超过 1 秒的操作 ### 6. 关闭阶段 (Shutdown) **时机**: - 宿主应用退出 - 轻应用被禁用 - 轻应用热重载 **职责**: 清理资源和保存状态 **轻应用代码示例**: ```csharp public class MyAirApp : IAirApp { private IDisposable? _eventSubscription; private HttpClient? _httpClient; private CancellationTokenSource? _cts; public async Task ShutdownAsync() { try { _logger.LogInformation($"{Name} is shutting down..."); // 1. 取消正在进行的操作 _cts?.Cancel(); // 2. 取消事件订阅 _eventSubscription?.Dispose(); // 3. 保存状态 await SaveStateAsync(); // 4. 释放资源 _httpClient?.Dispose(); // 5. 停止后台任务 await StopBackgroundServicesAsync(); _logger.LogInformation($"{Name} shutdown completed"); } catch (Exception ex) { _logger.LogError(ex, "Error during plugin shutdown"); // 不要抛出异常,避免影响其他轻应用 } } private async Task SaveStateAsync() { // 保存轻应用状态到设置 _context?.Settings.SetValue("LastUpdateTime", DateTime.Now); await Task.CompletedTask; } private async Task StopBackgroundServicesAsync() { // 停止定时任务等 await Task.CompletedTask; } } ``` **关闭最佳实践**: ```csharp public async Task ShutdownAsync() { try { // ✅ 尽快完成(< 3 秒) // ✅ 使用 try-catch 避免异常 // ✅ 按相反顺序清理资源 // ✅ 保存关键状态 // ❌ 不要抛出异常 // ❌ 不要执行耗时操作 // 取消异步操作 _cancellationTokenSource?.Cancel(); // 取消订阅(防止内存泄漏) UnsubscribeEvents(); // 释放托管资源 DisposeResources(); // 保存状态(快速) SaveCriticalState(); } catch (Exception ex) { // 记录但不抛出 _logger?.LogError(ex, "Shutdown error"); } } ``` **开发者注意事项**: - ✅ ShutdownAsync 必须快速完成(< 3 秒) - ✅ 取消所有异步操作 - ✅ 取消事件订阅(防止内存泄漏) - ✅ 释放所有 IDisposable 资源 - ✅ 保存关键状态 - ❌ 不要抛出异常 ## 生命周期事件 轻应用可以监听宿主的生命周期事件: ```csharp public class MyAirApp : IAirApp { public async Task InitializeAsync(IAirAppRuntimeContext context) { var hostLifecycle = context.Services .GetService(); if (hostLifecycle != null) { hostLifecycle.Starting += OnHostStarting; hostLifecycle.Started += OnHostStarted; hostLifecycle.Stopping += OnHostStopping; hostLifecycle.Stopped += OnHostStopped; } } private void OnHostStarting(object? sender, EventArgs e) { // 宿主正在启动 } private void OnHostStarted(object? sender, EventArgs e) { // 宿主已启动完成 } private void OnHostStopping(object? sender, EventArgs e) { // 宿主即将关闭 } private void OnHostStopped(object? sender, EventArgs e) { // 宿主已关闭 } public async Task ShutdownAsync() { // 取消订阅 var hostLifecycle = _context?.Services .GetService(); if (hostLifecycle != null) { hostLifecycle.Starting -= OnHostStarting; hostLifecycle.Started -= OnHostStarted; hostLifecycle.Stopping -= OnHostStopping; hostLifecycle.Stopped -= OnHostStopped; } } } ``` ## 错误处理 ### 初始化失败 如果轻应用初始化失败,宿主会: 1. 记录错误日志 2. 标记轻应用为"加载失败" 3. 继续加载其他轻应用 4. 在 UI 中显示失败状态 ### 运行时异常 组件代码中的未捕获异常: 1. 被宿主捕获并记录 2. 组件标记为"错误"状态 3. 组件停止更新 4. 不影响其他组件 ### 关闭超时 如果 ShutdownAsync 超过 5 秒: 1. 宿主强制终止 2. 记录超时警告 3. 继续关闭其他轻应用 ## 轻应用热重载 宿主支持轻应用热重载(开发中功能): ``` 1. 用户触发重载 ↓ 2. 调用 ShutdownAsync() ↓ 3. 卸载程序集 ↓ 4. 重新加载程序集 ↓ 5. 创建新实例 ↓ 6. 调用 InitializeAsync() ↓ 7. 恢复组件状态 ``` ## 小结 轻应用生命周期的关键点: - ✅ **发现**: 确保 airapp.json 正确 - ✅ **加载**: 管理好依赖关系 - ✅ **初始化**: 快速注册,耗时操作后台执行 - ✅ **运行**: 高效更新,异步处理 - ✅ **关闭**: 及时清理,避免异常 ## 下一步 - [组件系统详解](02-组件系统.md) - 学习组件开发 - [设置系统](03-设置系统.md) - 管理轻应用配置 - [轻应用通信](05-轻应用通信.md) - 轻应用间协作 - [IAirApp 接口](../03-API参考/01-IAirApp接口.md) - API 详细文档