Harmony OS NEXT初学笔记

一、熟悉概念

鸿蒙开发相关的一些概念,打开官网,看到的就是这几个套件

二、简单介绍

*   DevEco Studio:类似 Android Studio.
*   ArkTS:ArkTS 是鸿蒙生态的应用开发语言。

全称 TypeScript (简称TS)基本语法风格的基础上,对 TS 的动态类型特性施加更严格的约束,引入静态类型。 提供了声明式 UI、状态管理等相应的能力,可以更简洁、更自然的方式开发高性能应用。

*   ArkUI

ArkUI 是一套构建分布式应用界面的声明式 UI 开发框架。它使用极简的 UI 信息语法、丰富的 UI 组件、以及实时界面预览工具,帮助您提升 HarmonyOS 应用界面开发效率30%。您只需使用一套 ArkTS API,就能在多个 HarmonyOS 设备上提供生动而流畅的用户界面体验。

可以理解为用 TS 实现的一套 UI 组件库,包括常用的组件和布局等。

*   ArkCompiler:ArkCompiler 是华为自研的统一编程平台,包含编译器、工具链、运行时等关键部件,支持高级语言在多种芯片平台的编译与运行,并支撑应用和服务运行在手机、个人电脑、平板、电视、汽车和智能穿戴等多种设备上的需求。

用于将 TS 代码编译为鸿蒙系统可执行指令,俗称编译打包工具。

初识

准备IDE

按照官方教程,需要下载鸿蒙开发 IDE,也就是 DevEco Studio,和 AndroidStudio 长得差不多,比较容易上手。

首次启动,需要安装 Node.js、ohpm、Harmony OS SDK 等依赖,根据引导一直下一步即可。

完整依赖

*   Node.js:鸿蒙使用 TS 作为开发语言,需要 JS 运行环境。
*   ohpm:ohpm 全称 Open Harmony Package Manager,也就是鸿蒙上使用的包管理工具,类似Maven 仓库。(前端常用的包管理工具 应该叫npm)
*   Harmony OS SDK:相当于 Android 上的 Android SDK。

安装 有一点需要注意,IDE 仅支持特定版本的 Node.js,如果有安装比较高的或者较低的 版本 建议大家先卸载本地安装的 Node.js,通过 IDE 重新安装支持的版本,我自己安装的低版本也会报错

三、创建项目

配置完成后,新建一个项目,比较好的是 把光标放上去还会提示支持哪些设备

Ability 的概念,和 Android 中的 Activity 很像,暂且认为它就是一个页面吧,具体的我还没有学到

除了空页面之外,还支持关于、分类、网格、列表、登录、闪屏等模板。

支持的完整模板

项目配置页面(选择 Empty Ability 下一步)

*   Project name:项目名
*   Bundle name:项目唯一标志,类似于 Android 的 Package name
*   Save location:保存位置
*   Compile SDK:编译使用的 SDK 版本
*   Model:应用模型,有 Stage 和 FA 可选,官网推荐使用 Stage
*   Enable Super Visual:官方的解释是启用低代码开发,先不管它
*   Language:开发语言,Stage 模型只能选 ArkTS,FA 模型还可以选 JS
*   Compatible SDK:字面意思是兼容的的 SDK 版本,暂时不清楚是最低支持版本(minSdk)还是适配的版本(targetSdk)
*   Device type:支持的设备类型

点击 Finish 即可完成创建

创建完的项目结构

鸿蒙中支持多种 Module,常用的有以下两种:

*   Entry:相当于 Android 中的 App Module。
*   Library:相当于 Android 中的 Library Module,仅可被依赖,无法独立运行。

Stage模型简易结构

动手能力有限,只能粗糙的画一画 :-)

*   UIAbility:UIAbility 组件是一种包含 UI 界面的应用组件,主要用于和用户交互。UIAbility 组件是系统调度的基本单元,为应用提供绘制界面的窗口;一个 UIAbility 组件中可以通过多个页面来实现一个功能模块。每一个 UIAbility 组件实例,都对应于一个最近任务列表中的任务。  Android View绘制流程 onLayout onDraw onMesure
*   WindowStage:每个 UIAbility 类实例都会与一个 WindowStage 类实例绑定,提供应用进程内窗口管理器的作用。就是说 UIAbility 通过 WindowStage 持有了一个窗口,为 ArkUI 提供了绘制区域。
*   Context:Context 是应用中对象的上下文。。。其他还没有考虑到
*   Page:Ability 是一个窗口,不包含内容,而 Page 则是真正显示内容的载体,Page 需要依附于 Ability 才能显示。

上手

尝试开发 App 。

UI开发 
(类似Android jectpackCompose)

ArkUI 提供了官方组件和布局(举例栅格布局)

APP登录页面开发展示图片

简单介绍

  • 鸿蒙使用 struct 定义组件

  • 鸿蒙仅支持在 ArkUI 中使用除组件外的特定操作符 if-else、ForEach 、

  • 鸿蒙通过组件对象提供的方法设置属性

    Text("账号密码登录").fontSize(30).fontColor(Color.Black).width("90%").margin({ top: 20 })

页面配置路由跳转

Ability 和 page。

一般来说一个功能只需要一个 Ability  就够了,目前还没有涉及到多个Ability

page 跳转     (Android Activity启动模式)

鸿蒙提供了 Router 模块,通过 url 地址完成 page 之间的路由。

提供了两种跳转模式,分别是 router.pushUrl() 和 router.replaceUrl(),这两种模式决定了目标页是否会替换当前页。

*   router.pushUrl():目标页不会替换当前页,而是压入页面栈。这样可以保留当前页的状态,并且可以通过返回键或者调用 router.back() 方法返回到当前页。
*   router.replaceUrl():目标页会替换当前页,并销毁当前页。这样可以释放当前页的资源,并且无法返回到当前页。

同时,Router 模块提供了两种实例模式,分别是 Standard 和 Single。这两种模式决定了目标 url 是否会对应多个实例。

*   Standard:标准实例模式,也是默认情况下的实例模式。每次调用该方法都会新建一个目标页,并压入栈顶。
*   Single:单实例模式。即如果目标页的url在页面栈中已经存在同 url 页面,则离栈顶最近的同 url 页面会被移动到栈顶,并重新加载;如果目标页的 url 在页面栈中不存在同 url 页面,则按照标准模式跳转。

router.pushUrl({ url:"pages/Main",params:{userName: "name"}})  // 添加params属性,传递参数 }
可以通过调用 router.getParams() 方法来获取传递过来的参数。
获取传递过来的参数对象\
const params: object = router.getParams()
const userName: string = params\["userName"]; // 获取userName的值
重点:变量类型声明  String和string

网络请求

官方提供的 Httpm模块

{
  "module": {
    "name": "entry",
    "type": "entry",
    "description": "$string:module_desc",
    "mainElement": "EntryAbility",
  //添加网络权限
    "requestPermissions": [
      {
        "name": "ohos.permission.INTERNET"
      }
    ]
  }
}


  async httpWork(URL: string) {
    let httpRequest = http.createHttp();
    //添加订阅事件
    httpRequest.on('headersReceive', (header) => {
      console.info('header: ' + JSON.stringify(header));
    });


    let url = URL;
    //GET请求
    let promiseGet = httpRequest.request(// 请求url地址
      url, {
      // 请求方式
      method: http.RequestMethod.GET,
      // 链接超时 时间
      connectTimeout: 60000,
      //读取超时 时间
      readTimeout: 60000,
      // 指定返回数据类型
      expectDataType: http.HttpDataType.STRING,
      // 是否使用缓存
      usingCache: true,
      // 优先级  返回[1,1000] 默认为1
      priority: 1,
      // 使用协议
      usingProtocol: http.HttpProtocol.HTTP1_1,
      // 是否使用代理
      usingProxy: false,
      // 添加请求头
      header: {
        'Content-Type': 'application/json'
      }
    });

promiseGet.then((data) => {
      if (data.responseCode === http.ResponseCode.OK) {
       
      }
    }).catch((err) => {
      
    });
  }

    //POST请求
    let promisePost = httpRequest.request(// 请求url地址
      url, {
      // 请求方式
      method: http.RequestMethod.POST,
      //如果是POST请求 必须要有请求体
      extraData:{
        "userName":"zhoutao"
      },
      // 链接超时 时间
      connectTimeout: 60000,
      //读取超时 时间
      readTimeout: 60000,
      // 指定返回数据类型
      expectDataType: http.HttpDataType.STRING,
      // 是否使用缓存
      usingCache: true,
      // 优先级  返回[1,1000] 默认为1
      priority: 1,
      // 使用协议
      usingProtocol: http.HttpProtocol.HTTP1_1,
      // 是否使用代理
      usingProxy: false,
      // 添加请求头
      header: {
        'Content-Type': 'application/json'
      }
    });
  }
    promisePost.then((data) => {
      if (data.responseCode === http.ResponseCode.OK) {
     
      }
    }).catch((err) => {
     
    });
  }

//销毁
httpRequest.destroy();

 /**
   * 网络请求 简单封装
   * @param path
   * @param method
   * @param extraData
   * @returns
   */
 async requestSync<T>(URL: string, method: http.RequestMethod, extraData?: Object): Promise<Response<T>> {
    return new Promise<Response<T>>((resolve, reject) => {
      let url = "BaseUrl" + URL;
     if (method === http.RequestMethod.POST) {
        //因为POST请求必须要有请求体,所以增加一个判断
        extraData = {};
      }
      let httpRequest = http.createHttp();
      httpRequest.request(
        url, {
        method: method,
        expectDataType: http.HttpDataType.OBJECT,
        header: header,
        extraData: extraData
      },
        (err, data) => {
          let res = new Response<T>()
          if (!err && data.responseCode === 200) {
            Object.assign(res, data.result)
          } else {
            res.errorCode = data?.responseCode ?? -1
            res.errorMsg = err?.message ?? ""
          }
          resolve(res);
        }
      )
    })
  }
}

/**
 * 响应处理
 */
export class Response<T> {
  errorCode: code = 0
  errorMsg: string = ""
  data: T = null

  isSuccess(): boolean {
    return this.errorCode === 0
  }
}

数据持久化

App 的状态保存,主要分为 键值对(key value)、 有 Preference、(KVStore、SQL 数据库 使用方法 暂不介绍了)。

*   首选(Preferences)

通常用于保存应用的配置信息。数据通过文本的形式保存在设备中,应用使用过程中会将文本中的数据全量加载到内存中,所以访问速度快、效率高,但不适合需要存储大量数据的场景。

*   键值型数据库(KV-Store)

一种非关系型数据库,其数据以“键值”对的形式进行组织、索引和存储,其中“键”作为唯一标识符。适合很少数据关系和业务关系的业务数据存储,同时因其在分布式场景中降低了解决数据库版本兼容问题的复杂度,和数据同步过程中冲突解决的复杂度而被广泛使用。相比于关系型数据库,更容易做到跨设备跨版本兼容。

*   关系型数据库(RelationalStore)

一种关系型数据库,以行和列的形式存储数据,广泛用于应用中的关系型数据的处理,包括一系列的增、删、改、查等接口,开发者也可以运行自己定义的SQL语句来满足复杂业务场景的需要。

Preferences

接口如下

//初始化
function getPreferences(context: Context, name: string, callback: AsyncCallback<Preferences>): void;
//写入
put(key: string, value: ValueType, callback: AsyncCallback<void>): void;
//检查key和vlue 也就是键值对 key不能为空
has(key: string, callback: AsyncCallback<boolean>): void;
//根据key获取对应的值 如果数据为null 返回默认值
get(key: string, defValue: ValueType, callback: AsyncCallback<ValueType>): void;
//根据对应的key进行删除
delete(key: string, callback: AsyncCallback<void>): void;
//将数据异步存储 持久化
flush(callback: AsyncCallback<void>): void;
//删除初始化数据 持久话数据也会被删除
function deletePreferences(context: Context, name: string, callback: AsyncCallback<void>): void;

//订阅数据,如果相对应key的值发生变化时,会触发 Callback回调
on(type: 'change', callback: Callback<string>): void;
//取消订阅
off(type: 'change', callback?: Callback<string>): void;

用法基本和 Android 中的 SharedPreference 一致,重点是 提供了 on 、 off 来订阅数据变更。 遥遥领先\~\~\~\~

多线程

接口请求、数据存储、埋点上报等等,多线程的性能,直接影响了应用的流畅度。

TaskPool 和 Worker&#x20;

TaskPool 支持在主线程封装任务抛给任务队列,系统选择合适的工作线程,进行任务的分发及执行,再将结果返回给主线程,支持任务的执行、取消,工作线程数量上限为 4。

简单使用

import taskpool from '@ohos.taskpool';


/**
 * 执行多任务
 * @param dataSlice
 * @returns
 */
@Concurrent
function printArgs(args: number): number {

  return args;
}

function achieve(buffer: ArrayBuffer) {

  let number = buffer.byteLength / 3;

  let task1 = new taskpool.Task(printArgs, 100);
  let task2 = new taskpool.Task(printArgs, 200);
  let task3 = new taskpool.Task(printArgs, 300);

  taskpool.execute(task1, taskpool.Priority.LOW).then((value: Object) => {

  });
  taskpool.execute(task2, taskpool.Priority.MEDIUM).then((value: Object) => {

  });
  taskpool.execute(task3, taskpool.Priority.HIGH).then((value: Object) => {

  });

}

Java 中的 ThreadPool 比较类似。

Worker:暂时没有了解

开发体验

优点

*   易上手

*   系统 API 封装性高

系统 API 用起来比较方便。

*   TS 学习

可能对于前段开发来说更容易上手。

*   对于Android 开发

IDE 使用基本一致,其次系统架构和 API 定义也非常相似。

缺点

*   系统不开源:开发的时候看不到源码。
*   配套工具还未完善
*   开源框架较少

有待深入了解

more...

笔记到此结束

笔记比较早,项目开发初期草稿,可能落后华为目前的版本
 

评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值