HarmonyOS开发:卡片性能优化——渲染效率与内存控制

举报
Jack20 发表于 2026/06/27 22:35:44 2026/06/27
【摘要】 HarmonyOS开发:卡片性能优化——渲染效率与内存控制📌 核心要点:卡片是"常驻桌面"的UI组件,性能问题会被无限放大——渲染慢了用户天天看、内存高了系统天天杀、更新频了电量天天掉,优化不是可选项,是必选项。 背景与动机普通App卡一下,用户忍忍就过去了。卡片不行——它就在桌面上,用户每次解锁都能看到。卡片的性能问题不是"偶发体验差",是"持续恶心人"。更严重的是,卡片性能差会直接影...

HarmonyOS开发:卡片性能优化——渲染效率与内存控制

📌 核心要点:卡片是"常驻桌面"的UI组件,性能问题会被无限放大——渲染慢了用户天天看、内存高了系统天天杀、更新频了电量天天掉,优化不是可选项,是必选项。

背景与动机

普通App卡一下,用户忍忍就过去了。卡片不行——它就在桌面上,用户每次解锁都能看到。卡片的性能问题不是"偶发体验差",是"持续恶心人"。

更严重的是,卡片性能差会直接影响系统稳定性:

  • 内存占用高 → 系统杀进程 → 卡片白屏
  • 更新频率高 → 电量消耗快 → 用户卸载你的卡片
  • 渲染效率低 → 卡片显示延迟 → 用户以为卡片坏了

鸿蒙系统对卡片的性能管控非常严格。内存超限会被杀,CPU占用过高会被降频,更新太频繁会被限流。你不主动优化,系统就替你"优化"——直接干掉你的卡片。

那卡片性能优化到底优化什么?三个维度:

  1. 渲染效率:卡片UI绘制速度,影响显示延迟
  2. 内存控制:卡片占用的内存大小,影响进程存活
  3. 更新平衡:数据更新频率与电量的平衡,影响用户体验

核心原理

卡片性能瓶颈分析

flowchart TB
    A[卡片性能问题] --> B[渲染慢]
    A --> C[内存高]
    A --> D[电量消耗快]
    
    B --> B1[布局层级过深]
    B --> B2[图片资源过大]
    B --> B3[组件数量过多]
    
    C --> C1[数据缓存未清理]
    C --> C2[图片未压缩]
    C --> C3[定时器未释放]
    
    D --> D1[更新频率过高]
    D --> D2[不可见时仍在更新]
    D --> D3[网络请求过于频繁]
    
    classDef problem fill:#FCE4EC,stroke:#C62828,color:#B71C1C
    classDef cause fill:#FFF3E0,stroke:#E65100,color:#BF360C
    
    class A problem
    class B,C,D problem
    class B1,B2,B3,C1,C2,C3,D1,D2,D3 cause

性能指标与阈值

指标 推荐值 上限值 超限后果
静态卡片渲染时间 <100ms 500ms 显示延迟
动态卡片内存占用 <5MB 10MB 进程被杀
静态卡片内存占用 <1MB 2MB 数据更新失败
卡片数据大小 <512B 1KB 数据截断
图片资源大小 <20KB 50KB 加载失败
更新间隔 ≥5分钟 被系统限流
布局层级深度 ≤5层 8层 渲染卡顿

渲染管线与优化点

flowchart LR
    A[数据更新] --> B[布局计算]
    B --> C[组件树构建]
    C --> D[绘制指令生成]
    D --> E[渲染输出]
    
    A -.->|优化1:<br/>减少数据量| B
    B -.->|优化2:<br/>减少层级| C
    C -.->|优化3:<br/>减少组件| D
    D -.->|优化4:<br/>减少绘制| E
    
    classDef pipeline fill:#E3F2FD,stroke:#1565C0,color:#0D47A1
    classDef optimize fill:#E8F5E9,stroke:#2E7D32,color:#1B5E20
    
    class A,B,C,D,E pipeline
    class optimize

代码实战

基础用法:布局优化

布局优化是渲染效率的基础。层级越深、组件越多,渲染越慢。

反模式:深层嵌套

// ❌ 布局层级过深(6层)
Column() {
  Row() {
    Column() {
      Row() {
        Column() {
          Text('数据')  // 第6层
        }
      }
    }
  }
}

优化:扁平化布局

// ✅ 扁平化布局(3层)
Column() {
  Row() {
    Text('数据')  // 第3层
  }
}

反模式:组件数量过多

// ❌ 30个Text组件显示列表
Column() {
  Text(this.item1)
  Text(this.item2)
  Text(this.item3)
  // ... 30个Text
}

优化:精简显示

// ✅ 只显示前5条,更多跳转App查看
Column() {
  Text(this.item1)
  Text(this.item2)
  Text(this.item3)
  Text(this.item4)
  Text(this.item5)
  Text(`还有 ${this.remainingCount}`)
}

完整的优化布局示例

// OptimizedCard.ets —— 优化后的卡片布局
@Entry
@Component
struct OptimizedCard {
  @State title: string = ''
  @State mainValue: string = ''
  @State subtitle: string = ''
  @State extra1: string = ''
  @State extra2: string = ''
  @State updateTime: string = ''

  build() {
    // 使用Flex替代多层Column/Row嵌套
    Flex({ direction: FlexDirection.Column, justifyContent: FlexAlign.SpaceBetween }) {
      // 第一行:标题 + 更新时间
      Flex({ justifyContent: FlexAlign.SpaceBetween, alignItems: ItemAlign.Center }) {
        Text(this.title)
          .fontSize(14)
          .fontColor('#333333')
          .fontWeight(FontWeight.Bold)
          .maxLines(1)
          .textOverflow({ overflow: TextOverflow.Ellipsis })
          .layoutWeight(1)  // 弹性布局,避免硬编码宽度
        
        Text(this.updateTime)
          .fontSize(10)
          .fontColor('#AAAAAA')
          .flexShrink(0)  // 不压缩,保证显示
      }
      .width('100%')
      
      // 核心数据——大字号,一目了然
      Text(this.mainValue)
        .fontSize(36)
        .fontColor('#FF6B35')
        .fontWeight(FontWeight.Bold)
      
      // 辅助信息
      Text(this.subtitle)
        .fontSize(12)
        .fontColor('#666666')
        .maxLines(1)
        .textOverflow({ overflow: TextOverflow.Ellipsis })
      
      // 底部附加信息
      Flex({ justifyContent: FlexAlign.SpaceBetween }) {
        Text(this.extra1)
          .fontSize(11)
          .fontColor('#999999')
        
        Text(this.extra2)
          .fontSize(11)
          .fontColor('#999999')
      }
      .width('100%')
    }
    .width('100%')
    .height('100%')
    .padding(16)
    .backgroundColor('#FFFFFF')
    .borderRadius(16)
  }
}

优化要点:

  • 用Flex替代多层Column/Row嵌套,减少层级
  • 用layoutWeight/flexShrink替代硬编码宽度,避免重复计算
  • maxLines + textOverflow防止文本溢出导致布局重排
  • 核心数据大字号、辅助信息小字号,减少组件数量

进阶用法:内存控制与更新策略

内存控制和更新策略是卡片性能优化的核心。

// CardPerformanceManager.ets —— 卡片性能管理器
import { formProvider, formBindingData } from '@kit.AbilityKit'
import { hilog } from '@kit.PerformanceAnalysisKit'

class CardPerformanceManager {
  private static instance: CardPerformanceManager
  
  // 数据缓存——限制大小
  private dataCache: Map<string, { data: Record<string, string>; timestamp: number }> = new Map()
  private readonly MAX_CACHE_SIZE = 20  // 最多缓存20条
  
  // 更新节流——控制更新频率
  private lastUpdateTime: Map<string, number> = new Map()
  private readonly MIN_UPDATE_INTERVAL = 5 * 60 * 1000  // 5分钟
  
  // 可见性追踪——不可见时暂停更新
  private visibleCards: Set<string> = new Set()
  
  // 待更新队列——合并短时间内的多次更新
  private pendingUpdates: Map<string, Record<string, string>> = new Map()
  private flushTimer: number | null = null
  private readonly FLUSH_DELAY = 1000  // 1秒后批量更新
  
  static getInstance(): CardPerformanceManager {
    if (!CardPerformanceManager.instance) {
      CardPerformanceManager.instance = new CardPerformanceManager()
    }
    return CardPerformanceManager.instance
  }
  
  // ===== 缓存管理 =====
  
  // 写入缓存(LRU策略)
  putCache(key: string, data: Record<string, string>): void {
    // 超过上限,删除最旧的
    if (this.dataCache.size >= this.MAX_CACHE_SIZE) {
      let oldestKey = ''
      let oldestTime = Infinity
      
      this.dataCache.forEach((value, k) => {
        if (value.timestamp < oldestTime) {
          oldestTime = value.timestamp
          oldestKey = k
        }
      })
      
      if (oldestKey) {
        this.dataCache.delete(oldestKey)
      }
    }
    
    this.dataCache.set(key, { data, timestamp: Date.now() })
  }
  
  // 读取缓存
  getCache(key: string): Record<string, string> | null {
    const cached = this.dataCache.get(key)
    if (cached) {
      // 更新访问时间(LRU)
      cached.timestamp = Date.now()
      return cached.data
    }
    return null
  }
  
  // 清理过期缓存
  cleanExpiredCache(maxAge: number = 30 * 60 * 1000): void {
    const now = Date.now()
    const expiredKeys: string[] = []
    
    this.dataCache.forEach((value, key) => {
      if (now - value.timestamp > maxAge) {
        expiredKeys.push(key)
      }
    })
    
    expiredKeys.forEach(key => this.dataCache.delete(key))
    hilog.info(0x0000, 'PerfManager', `清理过期缓存: ${expiredKeys.length}`)
  }
  
  // ===== 更新节流 =====
  
  // 请求更新(带节流和合并)
  requestUpdate(formId: string, data: Record<string, string>): void {
    // 1. 检查可见性
    if (!this.visibleCards.has(formId)) {
      hilog.info(0x0000, 'PerfManager', `卡片不可见,跳过更新: ${formId}`)
      return
    }
    
    // 2. 合并待更新数据
    const existing = this.pendingUpdates.get(formId) || {}
    this.pendingUpdates.set(formId, { ...existing, ...data })
    
    // 3. 延迟批量更新
    if (!this.flushTimer) {
      this.flushTimer = setTimeout(() => {
        this.flushUpdates()
        this.flushTimer = null
      }, this.FLUSH_DELAY)
    }
  }
  
  // 执行批量更新
  private flushUpdates(): void {
    const now = Date.now()
    
    this.pendingUpdates.forEach((data, formId) => {
      // 检查更新间隔
      const lastUpdate = this.lastUpdateTime.get(formId) || 0
      if (now - lastUpdate < this.MIN_UPDATE_INTERVAL) {
        hilog.warn(0x0000, 'PerfManager', `更新间隔不足: ${formId}`)
        return
      }
      
      // 压缩数据——移除与缓存相同的字段
      const cached = this.getCache(formId)
      const compressedData = this.compressData(data, cached)
      
      // 如果没有变化,跳过更新
      if (Object.keys(compressedData).length === 0) {
        hilog.info(0x0000, 'PerfManager', `数据无变化,跳过更新: ${formId}`)
        return
      }
      
      // 执行更新
      const bindingData = formBindingData.createFormBindingData(compressedData)
      formProvider.updateForm(formId, bindingData)
        .then(() => {
          this.lastUpdateTime.set(formId, now)
          this.putCache(formId, compressedData)
          hilog.info(0x0000, 'PerfManager', `更新成功: ${formId}`)
        })
        .catch((err: Error) => {
          hilog.error(0x0000, 'PerfManager', `更新失败: ${formId}`)
        })
    })
    
    this.pendingUpdates.clear()
  }
  
  // 数据压缩——只传变化的字段
  private compressData(newData: Record<string, string>, cached: Record<string, string> | null): Record<string, string> {
    if (!cached) return newData
    
    const compressed: Record<string, string> = {}
    Object.keys(newData).forEach(key => {
      if (newData[key] !== cached[key]) {
        compressed[key] = newData[key]
      }
    })
    
    return compressed
  }
  
  // ===== 可见性管理 =====
  
  setCardVisible(formId: string, visible: boolean): void {
    if (visible) {
      this.visibleCards.add(formId)
    } else {
      this.visibleCards.delete(formId)
    }
  }
  
  // ===== 性能统计 =====
  
  getPerformanceStats(): PerformanceStats {
    return {
      cacheSize: this.dataCache.size,
      pendingUpdates: this.pendingUpdates.size,
      visibleCards: this.visibleCards.size,
      totalCards: this.lastUpdateTime.size
    }
  }
}

interface PerformanceStats {
  cacheSize: number
  pendingUpdates: number
  visibleCards: number
  totalCards: number
}

const perfManager = CardPerformanceManager.getInstance()
export default perfManager

完整示例:带性能监控的卡片

在生产环境中,你需要监控卡片的性能指标,及时发现和解决问题。

// PerformanceMonitor.ets —— 卡片性能监控
import { hilog } from '@kit.PerformanceAnalysisKit'

class PerformanceMonitor {
  private static instance: PerformanceMonitor
  
  // 渲染耗时统计
  private renderTimes: Map<string, number[]> = new Map()
  
  // 更新耗时统计
  private updateTimes: Map<string, number[]> = new Map()
  
  // 内存使用统计
  private memorySnapshots: Map<string, number[]> = new Map()
  
  static getInstance(): PerformanceMonitor {
    if (!PerformanceMonitor.instance) {
      PerformanceMonitor.instance = new PerformanceMonitor()
    }
    return PerformanceMonitor.instance
  }
  
  // 记录渲染开始
  startRender(formId: string): number {
    return Date.now()
  }
  
  // 记录渲染结束
  endRender(formId: string, startTime: number): void {
    const duration = Date.now() - startTime
    this.recordMetric(this.renderTimes, formId, duration)
    
    if (duration > 500) {
      hilog.warn(0x0000, 'PerfMonitor', `渲染耗时过长: ${formId}, ${duration}ms`)
    }
  }
  
  // 记录更新耗时
  recordUpdate(formId: string, duration: number): void {
    this.recordMetric(this.updateTimes, formId, duration)
    
    if (duration > 200) {
      hilog.warn(0x0000, 'PerfMonitor', `更新耗时过长: ${formId}, ${duration}ms`)
    }
  }
  
  // 记录内存使用
  recordMemory(formId: string, bytes: number): void {
    this.recordMetric(this.memorySnapshots, formId, bytes)
    
    if (bytes > 5 * 1024 * 1024) {  // 5MB
      hilog.warn(0x0000, 'PerfMonitor', `内存占用过高: ${formId}, ${(bytes / 1024 / 1024).toFixed(2)}MB`)
    }
  }
  
  // 记录指标
  private recordMetric(map: Map<string, number[]>, key: string, value: number): void {
    if (!map.has(key)) {
      map.set(key, [])
    }
    
    const arr = map.get(key)!
    arr.push(value)
    
    // 只保留最近50条
    if (arr.length > 50) {
      arr.shift()
    }
  }
  
  // 获取性能报告
  getReport(formId: string): PerformanceReport {
    return {
      avgRenderTime: this.getAverage(this.renderTimes.get(formId)),
      maxRenderTime: this.getMax(this.renderTimes.get(formId)),
      avgUpdateTime: this.getAverage(this.updateTimes.get(formId)),
      maxUpdateTime: this.getMax(this.updateTimes.get(formId)),
      avgMemory: this.getAverage(this.memorySnapshots.get(formId)),
      maxMemory: this.getMax(this.memorySnapshots.get(formId))
    }
  }
  
  private getAverage(arr: number[] | undefined): number {
    if (!arr || arr.length === 0) return 0
    return arr.reduce((a, b) => a + b, 0) / arr.length
  }
  
  private getMax(arr: number[] | undefined): number {
    if (!arr || arr.length === 0) return 0
    return Math.max(...arr)
  }
}

interface PerformanceReport {
  avgRenderTime: number
  maxRenderTime: number
  avgUpdateTime: number
  maxUpdateTime: number
  avgMemory: number
  maxMemory: number
}

const monitor = PerformanceMonitor.getInstance()
export default monitor

在FormAbility中使用性能监控:

// MonitoredFormAbility.ets
import { formBindingData, FormExtensionAbility, formProvider } from '@kit.AbilityKit'
import perfMonitor from './PerformanceMonitor'

export default class MonitoredFormAbility extends FormExtensionAbility {
  
  onAddForm(want: Want): formBindingData.FormBindingData {
    const formId = want.parameters?.['ohos.extra.param.key.form_identity'] as string
    
    // 开始监控
    const startTime = perfMonitor.startRender(formId)
    
    const data = this.getCardData(formId)
    const result = formBindingData.createFormBindingData(data)
    
    // 结束监控
    perfMonitor.endRender(formId, startTime)
    
    return result
  }
  
  onUpdateForm(formId: string): formBindingData.FormBindingData {
    const startTime = Date.now()
    
    const data = this.getCardData(formId)
    const result = formBindingData.createFormBindingData(data)
    
    perfMonitor.recordUpdate(formId, Date.now() - startTime)
    
    return result
  }
  
  onRemoveForm(formId: string): void {
    // 输出性能报告
    const report = perfMonitor.getReport(formId)
    hilog.info(0x0000, 'MonitoredForm', `卡片性能报告: ${formId}`)
    hilog.info(0x0000, 'MonitoredForm', `平均渲染: ${report.avgRenderTime.toFixed(0)}ms`)
    hilog.info(0x0000, 'MonitoredForm', `平均更新: ${report.avgUpdateTime.toFixed(0)}ms`)
  }
  
  private getCardData(formId: string): Record<string, string> {
    return { title: '示例数据' }
  }
}

踩坑与注意事项

坑1:图片是内存杀手

卡片里的图片是内存占用的大头。一张未压缩的PNG可能有几百KB,加载到内存后可能膨胀到几MB。

// ❌ 未压缩的图片
Image($r('app.media.weather_bg'))  // 可能500KB

// ✅ 压缩后的图片
// 1. 使用WebP格式替代PNG,体积减少50%+
// 2. 降低分辨率,卡片显示区域有限,不需要原图分辨率
// 3. 使用系统图标替代自定义图片
Image($r('sys.media.ohos_ic_public_weather'))  // 系统图标,零内存开销

图片优化建议:

  • 格式:WebP > PNG > JPG
  • 分辨率:2x2卡片最大360px宽,图片不需要超过720px
  • 大小:单张图片不超过20KB
  • 数量:单张卡片图片不超过3张

坑2:定时器泄漏

动态卡片里用的定时器,如果不在onRemoveForm里清理,会一直运行,持续消耗CPU和内存。

// ❌ 定时器未清理
let timer: number | null = null

onAddForm(want: Want): formBindingData.FormBindingData {
  timer = setInterval(() => {
    this.updateProgress()  // 一直运行
  }, 1000)
  return formBindingData.createFormBindingData({})
}

onRemoveForm(formId: string): void {
  // 忘了清理!
}

// ✅ 正确清理
onRemoveForm(formId: string): void {
  if (timer) {
    clearInterval(timer)
    timer = null
  }
}

坑3:数据差异更新

每次更新都传全量数据,即使大部分字段没变。这不仅浪费带宽,还增加渲染开销——系统要重新解析和比对所有字段。

// ❌ 全量更新
formProvider.updateForm(formId, formBindingData.createFormBindingData({
  city: '北京',        // 没变
  temperature: '26°',  // 没变
  weather: '晴',       // 没变
  humidity: '45%',     // 没变
  aqi: '42',           // 没变
  updateTime: '14:35'  // 只有这个变了
}))

// ✅ 差异更新——只传变化的字段
formProvider.updateForm(formId, formBindingData.createFormBindingData({
  updateTime: '14:35'  // 只传变化的
}))

但注意:差异更新有个前提——卡片布局必须能处理部分字段缺失的情况。如果卡片在onAddForm时收到了完整数据,后续updateForm只传部分数据,卡片应该只更新变化的字段,而不是丢失未传的字段。

静态卡片的行为是"合并更新"——新数据和旧数据合并,未传的字段保持不变。所以差异更新在静态卡片中是安全的。

坑4:不可见卡片的更新浪费

用户桌面可能有多页,有些卡片在第二页、第三页,用户根本看不到。更新这些不可见的卡片,纯属浪费CPU和电量。

// 利用6.0的onVisibilityChange回调
onVisibilityChange(formIds: string[], isVisible: boolean): void {
  formIds.forEach(formId => {
    if (isVisible) {
      // 卡片变为可见,恢复更新
      this.resumeUpdates(formId)
    } else {
      // 卡片变为不可见,暂停更新
      this.pauseUpdates(formId)
    }
  })
}

坑5:网络请求的电量消耗

卡片更新数据时发起网络请求,是电量消耗的主要来源。每次更新都发网络请求,5分钟一次,一天就是288次请求。

优化策略:

  1. 缓存优先:先读缓存,缓存过期才发网络请求
  2. 合并请求:多张卡片共享同一数据源,只发一次请求
  3. 条件请求:使用If-Modified-Since头,数据没变时不下载
  4. 压缩传输:服务端返回压缩后的数据
// 缓存优先策略
async function fetchWithCache(url: string, maxAge: number = 30 * 60 * 1000): Promise<string> {
  const cached = readFromCache(url)
  
  if (cached && Date.now() - cached.timestamp < maxAge) {
    // 缓存有效,直接返回
    return cached.data
  }
  
  // 缓存过期,发网络请求
  try {
    const response = await http.request(url)
    saveToCache(url, response.result)
    return response.result
  } catch (err) {
    // 网络失败,返回过期缓存(总比没有强)
    if (cached) return cached.data
    throw err
  }
}

HarmonyOS 6适配说明

  1. 渲染引擎性能提升:6.0的卡片渲染引擎做了重大优化,渲染速度提升约40%。主要优化点包括:增量渲染(只重绘变化的部分)、布局缓存(相同布局不重复计算)、绘制指令合并。

  2. 智能更新调度:6.0引入了基于用户行为的智能更新调度。系统会追踪用户查看卡片的频率,自动调整更新间隔。常看的卡片更新更频繁(但不超过5分钟),不常看的更新更少(可能延长到2-4小时)。

  3. 内存监控API:6.0新增了卡片内存监控API,你可以实时获取卡片的内存占用:

import { formProvider } from '@kit.AbilityKit'

// 6.0新增的内存监控
const memoryInfo = await formProvider.getFormMemoryInfo(formId)
console.log(`内存占用: ${(memoryInfo.totalBytes / 1024).toFixed(2)}KB`)
console.log(`图片内存: ${(memoryInfo.imageBytes / 1024).toFixed(2)}KB`)
console.log(`数据内存: ${(memoryInfo.dataBytes / 1024).toFixed(2)}KB`)
  1. 卡片性能评分:6.0的服务中心会根据卡片的性能表现给出评分。评分低的卡片会被降低推荐权重,甚至从服务中心下架。评分指标包括:渲染速度、内存占用、更新频率、崩溃率。

  2. 懒加载支持:6.0的动态卡片支持懒加载,卡片首次显示时只渲染可见区域,滚动时再加载其他区域。这对4×4等大尺寸卡片的渲染性能提升明显。

总结

卡片性能优化不是"锦上添花",是"生死攸关"。内存高了被杀,渲染慢了被骂,更新频了被卸载。三个维度——渲染效率、内存控制、更新平衡——每一个都要做到位。

核心要点回顾:

  • 布局扁平化,层级不超过5层
  • 图片压缩,单张不超过20KB
  • 缓存管理,LRU策略控制缓存大小
  • 更新节流,5分钟间隔+差异更新
  • 可见性感知,不可见时暂停更新
  • 定时器清理,onRemoveForm必须释放资源
  • 网络请求缓存优先,减少电量消耗
评估维度 说明
学习难度 ⭐⭐⭐⭐ 需要理解渲染管线、内存模型、电量管理
使用频率 ⭐⭐⭐⭐ 性能问题一旦出现就是持续性的
重要程度 ⭐⭐⭐⭐⭐ 性能差=被杀=卡片白屏=用户流失

下一篇是本系列最后一篇——完整元服务开发实战,从创建到发布的全流程。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。