在这里插入图片描述
在这里插入图片描述

引言

在人工智能与移动互联网深度融合的今天,AI问答类应用已经成为用户获取知识的重要途径。随着华为鸿蒙生态的持续发展和鸿蒙PC的发布,开发者面临着新的机遇——如何构建一款既能在鸿蒙手机上流畅运行,又能充分利用鸿蒙PC大屏优势的高质量AI应用?

本文将详细介绍一款基于ArkTS语言开发的AI百科问答助手应用,该应用不仅完美适配鸿蒙移动终端,还针对鸿蒙PC进行了深度优化,同时预留了Flutter框架迁移路径。我们将从项目架构设计、核心功能实现、性能优化等多个维度,深入剖析这款应用的技术亮点和开发实践。


一、项目概览:打造鸿蒙生态的AI知识问答新体验

1.1 应用定位与核心价值

本应用是一款面向鸿蒙生态的AI百科问答助手,旨在为用户提供便捷、准确、智能的知识查询服务。应用融合了现代UI设计理念与先进的AI技术,实现了以下核心价值:

  • 全场景适配:同时支持鸿蒙手机、平板和PC设备,一次开发,多端运行
  • 智能问答:基于内置Mock知识库,覆盖20+热门科技话题,离线即可使用
  • 本地持久化:提问历史自动保存,随时回顾学习内容
  • 极简界面:问题输入区与问答结果区分隔清晰,操作直观
  • 流畅体验:加载状态提示、平滑滚动,打造良好交互

1.2 技术栈选择

在技术栈选择上,我们经过了深入的调研和权衡:

维度 技术选型 选型理由
开发语言 ArkTS 鸿蒙原生语言,性能优异,生态支持完善
框架 HarmonyOS SDK 鸿蒙官方SDK,提供丰富的UI组件和系统能力
状态管理 @State 轻量级响应式状态管理方案,适合单页面应用
数据存储 @ohos.data.preferences 轻量级键值存储,适合历史记录持久化
UI设计 Material Design 现代设计语言,跨平台一致性体验

1.3 项目架构

应用采用单文件架构,所有代码集中在Index.ets中,结构清晰,易于维护:

entry/src/main/ets/pages/Index.ets
├── 接口定义(QARecord、MockEntry)
├── 状态管理(@State装饰器)
├── Mock知识库(22条百科知识)
├── 生命周期方法(aboutToAppear)
├── 业务逻辑(提问、清空、历史管理)
├── 数据持久化(loadHistory、saveHistory)
└── UI渲染(build方法)

二、核心技术实现:从接口定义到状态管理

2.1 接口定义

应用定义了两个核心接口,严格遵循ArkTS语法规范,禁止使用any类型:

interface QARecord {
  question: string;
  answer: string;
  timestamp: number;
}

interface MockEntry {
  keyword: string;
  answer: string;
}

设计亮点:

  • 明确的数据结构,便于类型检查和维护
  • 支持JSON序列化/反序列化,便于本地存储
  • QARecord包含时间戳,支持历史记录排序和展示

2.2 状态管理

应用仅使用@State装饰器实现轻量级状态管理:

@State question: string = '';           // 当前输入的问题
@State answer: string = '';             // AI返回的答案
@State isLoading: boolean = false;      // 加载状态
@State history: QARecord[] = [];        // 历史记录列表
@State errorText: string = '';          // 错误提示文本

状态管理优势:

  • 响应式更新:状态变化自动触发UI更新
  • 轻量级:无需引入复杂的状态管理库
  • 直观易懂:状态与UI组件直接绑定

2.3 Mock知识库

应用内置了22条百科知识,覆盖人工智能、计算机、互联网、区块链、量子计算等热门科技话题:

private readonly MOCK_ANSWERS: MockEntry[] = [
  { keyword: '人工智能', answer: '人工智能(Artificial Intelligence,简称AI)是计算机科学的一个分支...' },
  { keyword: '计算机', answer: '计算机是一种能够按照程序运行,自动、高速处理海量数据的现代化智能电子设备...' },
  { keyword: '互联网', answer: '互联网(Internet)是指21世纪之初网络与网络之间所串连成的庞大网络...' },
  // ... 更多知识条目
];

Mock方案优势:

  • 离线可用:无需网络连接即可运行
  • 快速响应:本地匹配,毫秒级响应
  • 便于截图:内容固定,截图展示效果稳定
  • 预留扩展:可随时接入真实AI服务

2.4 数据持久化

应用使用@ohos.data.preferences实现本地数据持久化:

private async saveHistory(): Promise<void> {
  if (!this.context) {
    return;
  }
  try {
    let prefs = await this.getPreferences();
    let stringList: Array<string> = [];
    for (let i = 0; i < this.history.length; i++) {
      let record = this.history[i];
      stringList.push(JSON.stringify(record));
    }
    await prefs.put(this.STORAGE_KEY, JSON.stringify(stringList));
    await prefs.flush();
  } catch (error) {
    console.error('保存历史记录失败');
  }
}

private async loadHistory(): Promise<void> {
  if (!this.context) {
    return;
  }
  try {
    let prefs = await this.getPreferences();
    let jsonStr: string = await prefs.get(this.STORAGE_KEY, '') as string;
    if (jsonStr.length > 0) {
      let stringList: Array<string> = JSON.parse(jsonStr) as Array<string>;
      let records: QARecord[] = [];
      for (let i = 0; i < stringList.length; i++) {
        let str: string = stringList[i];
        let data: QARecord = JSON.parse(str) as QARecord;
        records.push(data);
      }
      this.history = records;
    }
  } catch (error) {
    console.error('加载历史记录失败');
  }
}

持久化设计要点:

  • 字符串数组存储:避免直接存储对象数组导致的类型问题
  • Context注入:通过getContext(this)获取上下文
  • 异常处理:完善的try-catch,保证应用稳定性
  • 单例模式:Preferences实例缓存,避免重复创建

三、UI开发:打造极简而不简单的用户界面

3.1 界面布局设计

应用界面分为上下两个区域:

问题输入区

  • 标题栏(蓝色背景,白色文字)
  • 输入标签
  • TextInput输入框
  • 错误提示文本
  • 提问按钮和清空按钮

问答结果区

  • 结果标题和历史记录计数
  • 加载状态提示
  • AI回答内容展示
  • 历史记录列表(按时间倒序排列)

3.2 核心UI组件

应用严格遵守约束,仅使用系统原生组件:

build() {
  Column() {
    // 标题栏
    Row() {
      Text('AI百科问答助手')
        .fontSize(20)
        .fontWeight(FontWeight.Bold)
        .fontColor('#FFFFFF')
    }
    .width('100%')
    .height(56)
    .padding({ left: 16, right: 16 })
    .backgroundColor('#1976D2')

    // 输入区
    Column() {
      Text('输入问题')
        .fontSize(16)
        .fontColor('#333333')
        .margin({ top: 16, left: 16, right: 16, bottom: 8 })

      TextInput({ placeholder: '请输入你想了解的知识点...', text: this.question })
        .width('100%')
        .height(56)
        .fontSize(15)
        .padding({ left: 12, right: 12 })
        .backgroundColor('#FFFFFF')
        .borderRadius(8)
        .borderWidth(1)
        .borderColor('#E0E0E0')
        .margin({ left: 16, right: 16 })
        .onChange((value: string) => {
          this.question = value;
        })

      // 按钮区域
      Row() {
        Button('提问')
          .width('45%')
          .height(44)
          .fontSize(16)
          .fontColor('#FFFFFF')
          .backgroundColor('#1976D2')
          .borderRadius(8)
          .enabled(!this.isLoading)
          .onClick(() => {
            this.handleSubmit();
          })

        Blank().width('10%')

        Button('清空')
          .width('45%')
          .height(44)
          .fontSize(16)
          .fontColor('#666666')
          .backgroundColor('#F5F5F5')
          .borderRadius(8)
          .onClick(() => {
            this.clearAll();
          })
      }
      .width('100%')
      .margin({ left: 16, right: 16, top: 16 })
    }

    // 结果区(带滚动)
    Scroll() {
      Column() {
        // 结果内容和历史记录
      }
    }
    .scrollable(ScrollDirection.Vertical)
    .width('100%')
    .layoutWeight(1)
  }
}

UI设计亮点:

  • 极简风格:仅使用Column、Row、Text、TextInput、Button组件
  • 响应式布局:使用layoutWeight实现自适应
  • 滚动支持:结果区使用Scroll组件,支持内容溢出滚动
  • 状态驱动:根据isLoading、answer等状态动态渲染

3.3 交互逻辑

应用实现了完整的交互流程:

提问流程:

  1. 用户输入问题
  2. 点击"提问"按钮
  3. 验证输入非空
  4. 设置加载状态
  5. 延迟500ms模拟网络请求
  6. 匹配Mock答案
  7. 保存到历史记录
  8. 清空输入框

清空流程:

  1. 点击"清空"按钮
  2. 清空输入框、答案、错误提示
  3. 清空历史记录
  4. 保存空历史到本地存储

四、鸿蒙PC适配策略

4.1 响应式设计

随着鸿蒙PC的发布,应用需要针对大屏设备进行优化:

// 使用百分比和vp单位实现响应式布局
.width('100%')           // 宽度自适应
.height(56)              // 固定高度
.layoutWeight(1)         // 剩余空间填充
.padding({ left: 16, right: 16 })  // 固定内边距

4.2 大屏优化建议

针对鸿蒙PC大屏,可以进行以下优化:

// 建议的PC端优化方案
// 1. 增加输入框宽度
TextInput()
  .width('80%')  // PC端可使用更宽的输入框
  .height(56)

// 2. 使用Flex布局优化按钮区域
Row() {
  Button('提问')
    .width(120)  // PC端固定按钮宽度
  Blank().width(20)
  Button('清空')
    .width(120)
}
.justifyContent(FlexAlign.Center)  // 居中对齐

// 3. 结果区优化
Scroll() {
  Column() {
    // 历史记录可使用网格布局
  }
}
.width('70%')  // PC端限制内容宽度
.margin({ left: '15%', right: '15%' })  // 居中显示

4.3 多窗口支持

鸿蒙PC支持多窗口模式,应用需要处理窗口大小变化:

aboutToAppear(): void {
  this.context = getContext(this) as common.Context;
  this.loadHistory();
  
  // 监听窗口尺寸变化(伪代码,需根据实际API调整)
  /*
  window.on('resize', () => {
    // 根据窗口大小调整布局
    this.adjustLayout();
  });
  */
}

五、Flutter框架迁移路径

虽然当前应用使用ArkTS开发,但我们预留了完整的Flutter框架迁移路径。以下是迁移方案:

5.1 项目结构映射

ArkTS模块 Flutter模块 说明
Index.ets lib/main.dart 主页面
QARecord接口 QARecord类 数据模型
MockEntry接口 MockEntry类 Mock数据结构
@State StatefulWidget 状态管理
preferences shared_preferences 本地存储

5.2 状态管理迁移

ArkTS @State → Flutter StatefulWidget

// Flutter版本的状态管理
class _IndexState extends State<Index> {
  String question = '';
  String answer = '';
  bool isLoading = false;
  List<QARecord> history = [];
  String errorText = '';
  
  void handleSubmit() async {
    setState(() {
      isLoading = true;
    });
    
    // AI服务调用...
    
    setState(() {
      isLoading = false;
      answer = mockAnswer;
    });
  }
  
  
  Widget build(BuildContext context) {
    // UI构建...
  }
}

5.3 UI组件迁移

ArkTS组件 → Flutter Widget

// Flutter版本的输入区
Column(
  children: [
    const Text('输入问题'),
    TextField(
      decoration: const InputDecoration(
        hintText: '请输入你想了解的知识点...',
        border: OutlineInputBorder(),
      ),
      onChanged: (value) {
        setState(() {
          question = value;
        });
      },
    ),
    Row(
      children: [
        ElevatedButton(
          onPressed: handleSubmit,
          child: const Text('提问'),
        ),
        const SizedBox(width: 16),
        TextButton(
          onPressed: clearAll,
          child: const Text('清空'),
        ),
      ],
    ),
  ],
)

5.4 优势对比

维度 ArkTS Flutter
性能 原生性能,接近系统应用 JIT/AOT编译,性能优秀
生态 鸿蒙原生API丰富 跨平台,社区成熟
开发效率 声明式UI,学习曲线平缓 热重载,开发效率高
跨平台 鸿蒙全场景 iOS/Android/Web/Desktop
包体积 较小,只包含必要组件 较大,包含完整框架

六、网络API预留方案

应用预留了真实AI服务对接接口,可随时接入外部API:

// 预留的真实API对接代码
/*
import http from '@ohos.net.http';

private async fetchOnlineAnswer(question: string): Promise<string> {
  let httpRequest = http.createHttp();
  let response = await httpRequest.request(
    'https://api.example.com/chat/completions',
    {
      method: http.RequestMethod.POST,
      header: {
        'Content-Type': 'application/json',
        'Authorization': 'Bearer YOUR_API_KEY'
      },
      extraData: {
        'question': question
      }
    }
  );
  let result = JSON.parse(response.result as string);
  return result['answer'];
}
*/

API集成步骤:

  1. 取消注释上述代码
  2. 替换API地址和密钥
  3. 修改handleSubmit方法调用fetchOnlineAnswer
  4. 添加网络权限配置(已在module.json5中配置)

七、权限配置

应用已在module.json5中添加网络权限配置:

"module": {
  "name": "entry",
  "type": "entry",
  "requestPermissions": [
    {
      "name": "ohos.permission.INTERNET"
    }
  ],
  // ... 其他配置
}

权限说明:

  • ohos.permission.INTERNET:允许应用访问网络
  • 配置位置:module.json5的module层级
  • 自动向系统申请,无需用户手动授权

八、性能优化与最佳实践

8.1 性能优化策略

列表渲染优化
ForEach(this.history, (record: QARecord) => {
  // 渲染历史记录项
}, (record: QARecord) => record.timestamp.toString())

优化要点:

  • 唯一ID:确保ForEach的第三个参数返回唯一标识
  • 懒加载:ForEach默认支持懒加载,只渲染可见区域
状态更新优化
// 使用不可变更新策略
let newHistory: QARecord[] = [record];
for (let i = 0; i < this.history.length; i++) {
  newHistory.push(this.history[i]);
}
this.history = newHistory;

优化要点:

  • 不可变更新:创建新数组触发响应式更新
  • 精准更新:只更新需要改变的数据

8.2 最佳实践总结

代码规范
  1. 接口定义:使用interface显式定义数据结构,禁止any类型
  2. 状态管理:使用@State装饰器管理组件状态
  3. 异常处理:所有异步操作都要有try-catch
  4. 命名规范:使用驼峰命名法,接口名首字母大写
用户体验
  1. 加载状态:所有耗时操作都要有加载提示
  2. 错误提示:友好的错误信息,引导用户纠正
  3. 输入验证:非空检查,避免无效请求

九、应用特点总结

9.1 技术特点

  • 纯ArkTS实现:不依赖第三方框架,代码轻量化
  • 严格类型检查:全部使用interface接口,禁止any类型
  • 响应式状态管理:使用@State实现数据驱动UI
  • 本地持久化:基于@ohos.data.preferences保存历史记录
  • 离线可用:内置Mock知识库,无需网络即可运行

9.2 功能特点

  • 智能问答:输入任意知识点问题,AI给出条理清晰的解答
  • 清空功能:一键清空所有内容和历史记录
  • 历史记录:自动保存提问历史,支持回顾
  • 加载状态:友好的加载提示,提升交互体验
  • 输入验证:非空检查,避免无效操作

9.3 适配特点

  • 鸿蒙全场景:支持手机、平板、PC等多种设备
  • 极简UI:仅使用系统原生组件,界面简洁
  • 响应式布局:自适应不同屏幕尺寸
  • 流畅滚动:支持内容溢出滚动

十、未来规划与扩展方向

10.1 功能扩展

  1. 语音输入:集成鸿蒙语音识别能力
  2. 图片识别:支持拍照识别知识点
  3. 多语言支持:支持中英文切换
  4. 知识分类:按主题分类展示知识

10.2 技术升级

  1. 真实AI对接:接入OpenAI、百度文心一言等真实AI服务
  2. 数据库升级:从preferences升级到关系型数据库
  3. 性能监控:集成性能监控和日志系统
  4. 单元测试:添加完整的单元测试用例

10.3 生态整合

  1. 鸿蒙原子化服务:开发原子化服务版本
  2. 多设备协同:支持手机、平板、PC多端协同
  3. HarmonyOS NEXT适配:适配HarmonyOS NEXT纯血鸿蒙

十一、总结

本文详细介绍了基于ArkTS开发的AI百科问答助手应用,涵盖了从接口定义、状态管理、UI开发到数据持久化的全过程。应用严格遵守鸿蒙开发规范,仅使用系统原生组件,实现了完整的问答功能和本地存储能力。

核心技术亮点:

  1. 轻量级架构:单文件实现,代码结构清晰
  2. 严格类型检查:全部使用interface接口,禁止any类型
  3. 响应式状态管理:使用@State实现数据驱动UI更新
  4. 离线Mock方案:内置22条百科知识,无需网络即可运行
  5. 本地持久化:基于@ohos.data.preferences保存历史记录

鸿蒙生态优势:

  • 全场景适配:一次开发,多端运行
  • 原生性能:接近系统级应用的性能表现
  • 丰富API:访问鸿蒙系统的全部能力

无论是作为一款独立的AI问答应用,还是作为鸿蒙应用开发的学习案例,本项目都具有很高的参考价值。开发者可以基于此项目快速构建自己的AI应用,或学习鸿蒙应用开发的最佳实践。


附录:核心代码

完整Index.ets代码

import preferences from '@ohos.data.preferences';
import common from '@ohos.app.ability.common';

interface QARecord {
  question: string;
  answer: string;
  timestamp: number;
}

interface MockEntry {
  keyword: string;
  answer: string;
}

@Entry
@Component
struct Index {
  @State question: string = '';
  @State answer: string = '';
  @State isLoading: boolean = false;
  @State history: QARecord[] = [];
  @State errorText: string = '';
  
  private preferencesInst: preferences.Preferences | null = null;
  private context: common.Context | null = null;
  private readonly STORAGE_KEY: string = 'qa_history';

  private readonly MOCK_ANSWERS: MockEntry[] = [
    { keyword: '人工智能', answer: '人工智能(Artificial Intelligence,简称AI)是计算机科学的一个分支...' },
    { keyword: '计算机', answer: '计算机是一种能够按照程序运行...' },
    // ... 更多知识条目
  ];

  aboutToAppear(): void {
    this.context = getContext(this) as common.Context;
    this.loadHistory();
  }

  private async loadHistory(): Promise<void> {
    if (!this.context) {
      return;
    }
    try {
      let prefs = await this.getPreferences();
      let jsonStr: string = await prefs.get(this.STORAGE_KEY, '') as string;
      if (jsonStr.length > 0) {
        let stringList: Array<string> = JSON.parse(jsonStr) as Array<string>;
        let records: QARecord[] = [];
        for (let i = 0; i < stringList.length; i++) {
          let str: string = stringList[i];
          let data: QARecord = JSON.parse(str) as QARecord;
          records.push(data);
        }
        this.history = records;
      }
    } catch (error) {
      console.error('加载历史记录失败');
    }
  }

  private async saveHistory(): Promise<void> {
    if (!this.context) {
      return;
    }
    try {
      let prefs = await this.getPreferences();
      let stringList: Array<string> = [];
      for (let i = 0; i < this.history.length; i++) {
        let record = this.history[i];
        stringList.push(JSON.stringify(record));
      }
      await prefs.put(this.STORAGE_KEY, JSON.stringify(stringList));
      await prefs.flush();
    } catch (error) {
      console.error('保存历史记录失败');
    }
  }

  private async handleSubmit(): Promise<void> {
    if (this.question.trim().length === 0) {
      this.errorText = '请输入问题';
      return;
    }

    this.errorText = '';
    this.answer = '';
    this.isLoading = true;

    await this.delay(500);

    let mockAnswer: string = this.getMockAnswer(this.question);

    this.isLoading = false;
    this.answer = mockAnswer;

    let record: QARecord = {
      question: this.question.trim(),
      answer: mockAnswer,
      timestamp: Date.now()
    };

    let newHistory: QARecord[] = [record];
    for (let i = 0; i < this.history.length; i++) {
      newHistory.push(this.history[i]);
    }
    this.history = newHistory;

    await this.saveHistory();

    this.question = '';
  }

  build() {
    Column() {
      // 标题栏
      Row() {
        Text('AI百科问答助手')
          .fontSize(20)
          .fontWeight(FontWeight.Bold)
          .fontColor('#FFFFFF')
      }
      .width('100%')
      .height(56)
      .padding({ left: 16, right: 16 })
      .backgroundColor('#1976D2')

      // 输入区和结果区...
    }
    .width('100%')
    .height('100%')
  }
}

权限配置

{
  "module": {
    "name": "entry",
    "type": "entry",
    "requestPermissions": [
      {
        "name": "ohos.permission.INTERNET"
      }
    ]
  }
}

参考资料:

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐