Просмотр исходного кода

优化桌面卡片图片缓存

chendeben 1 год назад
Родитель
Сommit
82a38149c5

+ 178 - 5
entry/src/main/ets/common/widget/EnhancedFormUpdateService.ets

@@ -68,6 +68,7 @@ interface ProcessedImageInfo {
   fileName: string;
   memoryUri: string;
   fd: number;
+  sourceHash?: string;  // 添加源文件哈希用于缓存标识
 }
 
 /**
@@ -111,6 +112,12 @@ export class EnhancedFormUpdateService {
   private downloadingImages: Map<string, Promise<string | null>> = new Map();
   private readonly imageCacheExpiry: number = 24 * 60 * 60 * 1000; // 24小时
   private readonly maxCacheSize: number = 50; // 最多缓存50张图片
+  
+  // 本地图片处理缓存
+  private localImageCache: Map<string, ProcessedImageInfo> = new Map();
+  private processingLocalImages: Map<string, Promise<ProcessedImageInfo | null>> = new Map();
+  private readonly localImageCacheExpiry: number = 30 * 60 * 1000; // 30分钟
+  private lastLocalCacheCleanup: number = 0;
 
   // 性能统计
   private updateStats: UpdateStats = {
@@ -450,6 +457,66 @@ export class EnhancedFormUpdateService {
   private async processLocalImageFile(fileUri: string): Promise<ProcessedImageInfo | null> {
     try {
       hilog.info(0x0000, TAG, `📷 Processing local image file: ${fileUri}`);
+      
+      // 生成缓存键(基于URI和时间戳)
+      const cacheKey = this.generateLocalImageCacheKey(fileUri);
+      
+      // 检查本地图片缓存
+      const cachedInfo = this.localImageCache.get(cacheKey);
+      if (cachedInfo) {
+        // 验证缓存的文件是否还存在
+        const tempFilePath = `${this.appContext!.getApplicationContext().tempDir}/${cachedInfo.fileName}`;
+        if (fileIo.accessSync(tempFilePath)) {
+          hilog.info(0x0000, TAG, `📷 Using cached local image: ${cachedInfo.fileName}`);
+          return cachedInfo;
+        } else {
+          // 缓存文件不存在,移除缓存项
+          this.localImageCache.delete(cacheKey);
+          hilog.warn(0x0000, TAG, `📷 Cached file not found, will reprocess: ${cachedInfo.fileName}`);
+        }
+      }
+      
+      // 检查是否正在处理中
+      if (this.processingLocalImages.has(cacheKey)) {
+        hilog.info(0x0000, TAG, `📷 Image already being processed, waiting: ${fileUri}`);
+        return await this.processingLocalImages.get(cacheKey)!;
+      }
+      
+      // 创建处理Promise
+      const processingPromise = this.performLocalImageProcessing(fileUri, cacheKey);
+      this.processingLocalImages.set(cacheKey, processingPromise);
+      
+      try {
+        const result = await processingPromise;
+        return result;
+      } finally {
+        this.processingLocalImages.delete(cacheKey);
+      }
+      
+    } catch (error) {
+      hilog.error(0x0000, TAG, `❌ Failed to process local image: ${error}`);
+      return null;
+    }
+  }
+  
+  /**
+   * 生成本地图片缓存键
+   */
+  private generateLocalImageCacheKey(fileUri: string): string {
+    // 从URI中提取文件名或路径的关键部分作为缓存键
+    const pathParts = fileUri.split('/');
+    const fileName = pathParts[pathParts.length - 1];
+    // 使用文件名作为缓存键(因为日志显示相同的文件被重复处理)
+    return `local_${fileName}`;
+  }
+  
+  /**
+   * 执行本地图片处理
+   */
+  private async performLocalImageProcessing(fileUri: string, cacheKey: string): Promise<ProcessedImageInfo | null> {
+    try {
+      // 清理过期缓存
+      this.cleanupLocalImageCache();
 
       // 转换 file:// URI 为实际文件路径
       // file://com.xgplayer.ttmusic.hm/data/storage/el2/base/haps/entry/files/xxx.jpg
@@ -523,9 +590,14 @@ export class EnhancedFormUpdateService {
       const result: ProcessedImageInfo = {
         fileName,
         memoryUri,
-        fd
+        fd,
+        sourceHash: cacheKey
       };
       
+      // 添加到缓存
+      this.localImageCache.set(cacheKey, result);
+      hilog.info(0x0000, TAG, `📷 Added to local image cache: ${cacheKey}`);
+      
       return result;
 
     } catch (error) {
@@ -541,6 +613,72 @@ export class EnhancedFormUpdateService {
     return url.startsWith('file://');
   }
 
+  /**
+   * 清理本地图片缓存
+   */
+  private cleanupLocalImageCache(): void {
+    const now = Date.now();
+    
+    // 每5分钟清理一次
+    if (now - this.lastLocalCacheCleanup < 5 * 60 * 1000) {
+      return;
+    }
+    
+    this.lastLocalCacheCleanup = now;
+    
+    // 清理过期的缓存项
+    const keysToDelete: string[] = [];
+    const tempDir = this.appContext!.getApplicationContext().tempDir;
+    
+    this.localImageCache.forEach((info, key) => {
+      const tempFilePath = `${tempDir}/${info.fileName}`;
+      
+      // 检查文件是否存在
+      if (!fileIo.accessSync(tempFilePath)) {
+        keysToDelete.push(key);
+        hilog.info(0x0000, TAG, `📷 Removing cache entry for missing file: ${info.fileName}`);
+      }
+    });
+    
+    // 如果缓存过大,删除最旧的项
+    if (this.localImageCache.size > 20) {
+      const sortedEntries = Array.from(this.localImageCache.entries())
+        .sort((a, b) => {
+          // 根据文件名中的时间戳排序
+          const timeA = parseInt(a[1].fileName.split('_')[2] || '0');
+          const timeB = parseInt(b[1].fileName.split('_')[2] || '0');
+          return timeA - timeB;
+        });
+      
+      const entriesToDelete = sortedEntries.slice(0, this.localImageCache.size - 15);
+      entriesToDelete.forEach((entry) => {
+        const key = entry[0];
+        const info = entry[1];
+        keysToDelete.push(key);
+        // 尝试删除临时文件
+        try {
+          const filePath = `${tempDir}/${info.fileName}`;
+          if (fileIo.accessSync(filePath)) {
+            fileIo.closeSync(info.fd);
+            fileIo.unlinkSync(filePath);
+            hilog.info(0x0000, TAG, `📷 Deleted old cached file: ${info.fileName}`);
+          }
+        } catch (error) {
+          hilog.warn(0x0000, TAG, `📷 Failed to delete cached file: ${info.fileName}`);
+        }
+      });
+    }
+    
+    // 删除缓存项
+    keysToDelete.forEach(key => {
+      this.localImageCache.delete(key);
+    });
+    
+    if (keysToDelete.length > 0) {
+      hilog.info(0x0000, TAG, `📷 Cleaned up ${keysToDelete.length} local image cache entries`);
+    }
+  }
+  
   /**
    * 获取文件扩展名
    */
@@ -561,12 +699,21 @@ export class EnhancedFormUpdateService {
     }
 
     try {
-      // 如果已经是 memory:// 格式(本地图片已处理),直接返回
+      // 如果已经是 memory:// 格式(本地图片已处理),验证缓存是否有效
       if (adaptedData.coverImage.startsWith('memory://')) {
-        hilog.info(0x0000, TAG, `📷 Image already processed as memory URI: ${adaptedData.coverImage}`);
         const fileName = adaptedData.coverImage.replace('memory://', '');
-        adaptedData.imgName = fileName;
-        return;
+        const tempFilePath = `${this.appContext!.getApplicationContext().tempDir}/${fileName}`;
+        
+        // 验证文件是否存在
+        if (fileIo.accessSync(tempFilePath)) {
+          hilog.info(0x0000, TAG, `📷 Using existing memory URI: ${adaptedData.coverImage}`);
+          adaptedData.imgName = fileName;
+          return;
+        } else {
+          hilog.warn(0x0000, TAG, `📷 Memory URI file not found, will reprocess: ${fileName}`);
+          // 清除无效的memory URI,继续处理
+          adaptedData.coverImage = '';
+        }
       }
 
       // 处理网络图片
@@ -948,6 +1095,32 @@ export class EnhancedFormUpdateService {
     };
     
   }
+  
+  /**
+   * 清理所有缓存
+   */
+  public clearAllCaches(): void {
+    // 清理本地图片缓存
+    this.localImageCache.forEach((info) => {
+      try {
+        const tempFilePath = `${this.appContext!.getApplicationContext().tempDir}/${info.fileName}`;
+        if (fileIo.accessSync(tempFilePath)) {
+          fileIo.closeSync(info.fd);
+          fileIo.unlinkSync(tempFilePath);
+        }
+      } catch (error) {
+        hilog.warn(0x0000, TAG, `Failed to clean cached file: ${info.fileName}`);
+      }
+    });
+    this.localImageCache.clear();
+    this.processingLocalImages.clear();
+    
+    // 清理网络图片缓存
+    this.imageCache.clear();
+    this.downloadingImages.clear();
+    
+    hilog.info(0x0000, TAG, '🧹 All caches cleared');
+  }
 
   /**
    * 强制刷新所有卡片(忽略防抖)

+ 1 - 1
entry/src/main/ets/widget/pages/PlayerWidgetMedium.ets

@@ -32,7 +32,7 @@ let storageUpdateCall = new LocalStorage();
 @Component
 struct PlayerWidgetMedium {
   // 卡片数据属性 - 使用LocalStorageProp与FormExtensionAbility通信
-  @LocalStorageProp('formId') formId: string = '12400633174999288';
+  @LocalStorageProp('formId') formId: string = '202501';
   @LocalStorageProp('isPlaying') isPlaying: boolean = false;
   @LocalStorageProp('songTitle') songTitle: string = 'Dream It Possible';
   @LocalStorageProp('songArtist') songArtist: string = 'Delacey';

+ 1 - 1
entry/src/main/ets/widget/pages/PlayerWidgetSmall.ets

@@ -8,7 +8,7 @@
 @Component
 struct PlayerWidgetSmall {
   // 卡片数据属性 - 使用LocalStorageProp与FormExtensionAbility通信
-  @LocalStorageProp('formId') formId: string = '12400633174999288';
+  @LocalStorageProp('formId') formId: string = '202502';
   @LocalStorageProp('isPlaying') isPlaying: boolean = false;
   @LocalStorageProp('hasNext') hasNext: boolean = false;
   @LocalStorageProp('hasPrevious') hasPrevious: boolean = false;

+ 1 - 1
entry/src/main/ets/widget/pages/PlayerWidgetSquare.ets

@@ -25,7 +25,7 @@ const PlayAlignRules: Record<string, Record<string, string | VerticalAlign | Hor
 @Component
 struct PlayerWidgetSquare {
   // 卡片数据属性 - 使用LocalStorageProp与FormExtensionAbility通信
-  @LocalStorageProp('formId') formId: string = '12400633174999288';
+  @LocalStorageProp('formId') formId: string = '202503';
   @LocalStorageProp('isPlaying') isPlaying: boolean = false;
   @LocalStorageProp('songTitle') songTitle: string = 'Dream It Possible';
   @LocalStorageProp('songArtist') songArtist: string = 'Delacey';