Harmony学习之性能优化实战

Harmony学习之性能优化实战

一、场景引入

小明开发的新闻阅读应用在测试时发现以下问题:应用启动慢、列表滑动卡顿、内存占用高。用户反馈应用体验不佳,急需进行性能优化。HarmonyOS提供了丰富的性能优化工具和方法,帮助开发者提升应用质量。

二、核心优化维度

1. 性能指标定义

HarmonyOS应用性能主要关注以下指标:

指标 标准值 测量工具
应用启动时间 < 800ms HiTraceMeter
界面刷新率 ≥ 60fps 性能监视器
内存占用 < 200MB 内存分析工具
电量消耗 < 5%/h 电量分析工具
包体大小 < 20MB 构建分析

三、关键优化技术

1. 启动优化实践

优化首页加载速度:

// entry/src/main/ets/pages/HomePage.ets
@Component
struct HomePage {
  @State newsList: NewsItem[] = [];
  @State loaded: boolean = false;
  private lazyLoadTask: number | null = null;

  aboutToAppear() {
    // 延迟加载非关键资源
    this.lazyLoadTask = setTimeout(() => {
      this.loadInitialData();
    }, 100);
  }

  aboutToDisappear() {
    if (this.lazyLoadTask) {
      clearTimeout(this.lazyLoadTask);
    }
  }

  async loadInitialData() {
    // 1. 优先加载可见区域数据
    const initialData = await this.loadFirstScreenData();
    this.newsList = initialData;
    this.loaded = true;
    
    // 2. 延迟加载剩余数据
    setTimeout(() => {
      this.loadRemainingData();
    }, 300);
  }

  async loadFirstScreenData(): Promise<NewsItem[]> {
    // 只加载前5条,保证首屏快速显示
    return await NewsService.getNews(0, 5);
  }

  async loadRemainingData() {
    const moreData = await NewsService.getNews(5, 20);
    this.newsList = [...this.newsList, ...moreData];
  }

  build() {
    Column() {
      if (!this.loaded) {
        // 骨架屏占位
        this.buildSkeleton();
      } else {
        this.buildContent();
      }
    }
  }

  @Builder
  buildSkeleton() {
    Column() {
      ForEach([1, 2, 3, 4, 5], (index) => {
        Row() {
          Column() {
            Row()
              .width('100%')
              .height(20)
              .backgroundColor('#F0F0F0')
              .margin({ bottom: 8 })
            
            Row()
              .width('60%')
              .height(15)
              .backgroundColor('#F0F0F0')
          }
          .layoutWeight(1)
          .margin({ right: 10 })
          
          Row()
            .width(80)
            .height(60)
            .backgroundColor('#F0F0F0')
        }
        .padding(10)
        .margin({ bottom: 10 })
      })
    }
  }
}

2. 列表渲染优化

优化长列表性能:

// entry/src/main/ets/components/OptimizedList.ets
@Component
struct OptimizedList {
  @Prop newsList: NewsItem[] = [];
  private itemHeights: Map<number, number> = new Map();

  // 使用缓存避免重复计算
  getItemHeight(index: number): number {
    if (this.itemHeights.has(index)) {
      return this.itemHeights.get(index)!;
    }
    
    const item = this.newsList[index];
    const height = this.calculateHeight(item);
    this.itemHeights.set(index, height);
    return height;
  }

  // 简化高度计算逻辑
  private calculateHeight(item: NewsItem): number {
    const titleLines = Math.ceil(item.title.length / 30);
    const summaryLines = Math.ceil(item.summary.length / 50);
    return 20 + (titleLines + summaryLines) * 20 + 60;
  }

  // 优化ItemBuilder
  @Builder
  buildListItem(item: NewsItem, index: number) {
    ListItem() {
      Row() {
        // 使用LazyForEach加载图片
        if (item.imageUrl) {
          LazyImage({ uri: item.imageUrl })
            .width(80)
            .height(60)
            .borderRadius(5)
            .margin({ right: 10 })
        }
        
        Column() {
          Text(item.title)
            .fontSize(16)
            .maxLines(2)
            .textOverflow({ overflow: TextOverflow.Ellipsis })
            .margin({ bottom: 5 })
          
          Text(item.summary)
            .fontSize(14)
            .maxLines(3)
            .textOverflow({ overflow: TextOverflow.Ellipsis })
            .fontColor(Color.Gray)
        }
        .layoutWeight(1)
      }
      .padding(10)
    }
    .height(this.getItemHeight(index)) // 设置固定高度提升性能
  }

  build() {
    List({ space: 5 }) {
      LazyForEach(this.newsList, (item: NewsItem, index: number) => {
        this.buildListItem(item, index);
      })
    }
    .cachedCount(5) // 缓存5个屏幕外的Item
    .listDirection(Axis.Vertical)
  }
}

// 懒加载图片组件
@Component
struct LazyImage {
  @Prop uri: string = '';
  @State loaded: boolean = false;
  @State showPlaceholder: boolean = true;
  private loadingTask: number | null = null;

  aboutToAppear() {
    this.startLazyLoad();
  }

  aboutToDisappear() {
    this.cancelLoading();
  }

  startLazyLoad() {
    // 延迟加载图片
    this.loadingTask = setTimeout(() => {
      this.loadImage();
    }, 200);
  }

  async loadImage() {
    if (!this.uri) {
      this.showPlaceholder = false;
      return;
    }

    try {
      // 实际项目中应该使用图片加载库
      this.loaded = true;
      this.showPlaceholder = false;
    } catch (error) {
      console.error('图片加载失败:', error);
    }
  }

  cancelLoading() {
    if (this.loadingTask) {
      clearTimeout(this.loadingTask);
    }
  }

  build() {
    Stack() {
      if (this.showPlaceholder) {
        // 占位图
        Row()
          .width('100%')
          .height('100%')
          .backgroundColor('#F0F0F0')
      }
      
      if (this.loaded) {
        // 实际图片
        Image(this.uri)
          .width('100%')
          .height('100%')
          .objectFit(ImageFit.Cover)
      }
    }
  }
}

3. 内存优化策略

优化图片内存使用:

// entry/src/main/ets/utils/MemoryOptimizer.ets
import image from '@ohos.multimedia.image';

export class MemoryOptimizer {
  // 压缩图片到合适尺寸
  static async compressImage(
    pixelMap: image.PixelMap,
    maxWidth: number = 800,
    maxHeight: number = 600
  ): Promise<image.PixelMap> {
    const scale = Math.min(maxWidth / pixelMap.width, maxHeight / pixelMap.height);
    
    if (scale >= 1) {
      return pixelMap; // 不需要压缩
    }

    const operations: image.ImageOperation[] = [{
      operationType: image.OperationType.SCALE,
      scaleOptions: {
        scaleX: scale,
        scaleY: scale
      }
    }];

    return await image.applyOperations(pixelMap, operations);
  }

  // 清理图片缓存
  static clearImageCache(cache: Map<string, any>): void {
    const now = Date.now();
    const maxAge = 5 * 60 * 1000; // 5分钟
    
    for (const [key, value] of cache.entries()) {
      if (now - value.timestamp > maxAge) {
        cache.delete(key);
        if (value.pixelMap && value.pixelMap.release) {
          value.pixelMap.release();
        }
      }
    }
  }
}

4. 网络请求优化

// entry/src/main/ets/utils/NetworkOptimizer.ets
import http from '@ohos.net.http';

export class NetworkOptimizer {
  private static cache = new Map<string, { data: any, timestamp: number }>();
  private static pendingRequests = new Map<string, Promise<any>>();

  // 带缓存的网络请求
  static async requestWithCache(
    url: string,
    options?: http.HttpRequestOptions,
    cacheTime: number = 300000 // 5分钟缓存
  ): Promise<any> {
    const cacheKey = `${url}_${JSON.stringify(options)}`;
    
    // 检查缓存
    const cached = this.cache.get(cacheKey);
    if (cached && (Date.now() - cached.timestamp) < cacheTime) {
      return cached.data;
    }
    
    // 检查是否有相同请求正在进行
    if (this.pendingRequests.has(cacheKey)) {
      return await this.pendingRequests.get(cacheKey)!;
    }
    
    // 发起新请求
    const requestPromise = this.makeRequest(url, options);
    this.pendingRequests.set(cacheKey, requestPromise);
    
    try {
      const data = await requestPromise;
      
      // 缓存结果
      this.cache.set(cacheKey, {
        data,
        timestamp: Date.now()
      });
      
      return data;
    } finally {
      this.pendingRequests.delete(cacheKey);
    }
  }

  private static async makeRequest(
    url: string,
    options?: http.HttpRequestOptions
  ): Promise<any> {
    const httpRequest = http.createHttp();
    
    try {
      const response = await httpRequest.request(url, {
        method: options?.method || http.RequestMethod.GET,
        readTimeout: 10000, // 10秒超时
        connectTimeout: 5000, // 5秒连接超时
        ...options
      });
      
      if (response.responseCode === 200) {
        return JSON.parse(response.result.toString());
      } else {
        throw new Error(`请求失败: ${response.responseCode}`);
      }
    } finally {
      httpRequest.destroy();
    }
  }
}

四、实战案例:优化新闻阅读应用

1. 性能监控组件

// entry/src/main/ets/components/PerformanceMonitor.ets
@Component
struct PerformanceMonitor {
  @State fps: number = 0;
  @State memory: number = 0;
  @State cpu: number = 0;
  private frameCount: number = 0;
  private lastTime: number = 0;
  private monitorTask: number | null = null;

  aboutToAppear() {
    this.startMonitoring();
  }

  aboutToDisappear() {
    this.stopMonitoring();
  }

  startMonitoring() {
    this.lastTime = Date.now();
    
    this.monitorTask = setInterval(() => {
      this.updateMetrics();
    }, 1000);
  }

  updateMetrics() {
    // 计算FPS
    const now = Date.now();
    const elapsed = now - this.lastTime;
    this.fps = Math.round((this.frameCount * 1000) / elapsed);
    this.frameCount = 0;
    this.lastTime = now;
    
    // 获取内存和CPU信息
    this.updateSystemMetrics();
  }

  async updateSystemMetrics() {
    try {
      const systemMetrics = await this.getSystemMetrics();
      this.memory = systemMetrics.memory;
      this.cpu = systemMetrics.cpu;
    } catch (error) {
      console.error('获取系统指标失败:', error);
    }
  }

  onFrame() {
    this.frameCount++;
  }

  stopMonitoring() {
    if (this.monitorTask) {
      clearInterval(this.monitorTask);
    }
  }

  build() {
    Column() {
      Row() {
        Text(`FPS: ${this.fps}`)
          .fontSize(12)
          .fontColor(this.fps < 50 ? Color.Red : Color.Green)
        
        Text(`内存: ${this.memory.toFixed(1)}MB`)
          .fontSize(12)
          .margin({ left: 20 })
        
        Text(`CPU: ${this.cpu.toFixed(1)}%`)
          .fontSize(12)
          .margin({ left: 20 })
      }
      .padding(5)
      .backgroundColor(Color.Black)
    }
  }
}

五、最佳实践

1. 代码分割与懒加载

// module.json5
{
  "module": {
    "name": "entry",
    "type": "entry",
    "deliveryWithInstall": true,
    "installationFree": false,
    "pages": "$profile:main_pages.json",
    "abilities": [
      {
        "name": "EntryAbility",
        "srcEntry": "./ets/entryability/EntryAbility.ets",
        "launchType": "standard"
      },
      {
        "name": "DetailAbility",
        "srcEntry": "./ets/detailability/DetailAbility.ets",
        "launchType": "standard",
        "visible": false
      }
    ],
    "extensionAbilities": [
      {
        "name": "ServiceExtAbility",
        "srcEntry": "./ets/serviceextability/ServiceExtAbility.ets",
        "type": "service"
      }
    ]
  }
}

2. 图片资源优化

  • 使用WebP格式替代PNG/JPG
  • 实现图片懒加载
  • 使用合适的图片尺寸
  • 实现渐进式加载

六、总结

性能优化是一个持续的过程,需要在实际开发中不断监控和优化。建议:

  1. 监控先行:在开发阶段就集成性能监控
  2. 渐进优化:从影响最大的问题开始优化
  3. 定期检查:定期使用性能分析工具检查应用
  4. 用户反馈:关注用户反馈的性能问题

通过合理的优化策略,可以显著提升应用性能和用户体验。

posted @ 2025-12-23 23:21  J_____P  阅读(0)  评论(0)    收藏  举报