鸿蒙5.0开发【自定义全局组件 UI 构建异常问题和解决】

在之前的文章中([鸿蒙自定义 Dialog 的 6 种方式]),提到了自定义 Dialog 某些情况下无法渲染显示的问题,其本质是 UI 组件构造时,UI 上下文获取异常,一般在异步回调或者非 UI 组件环境中构造全局类的组件(例如弹窗或者 HUD)时,容易遇到这个问题。

1. 问题复现

使用我的 [XTEasyHUD],不预先在 UI 组件生命周期中对其进行初始化配置,直接在异步场景中调用,就会导致 HUD 无法显示。

ts
 代码解读
复制代码
import axios, { AxiosResponse } from '@ohos/axios'
import {
  XTEasyHUD
} from '@jxt/xt_hud'

class viewModel {
  async asyncShowToast() {
    let response: AxiosResponse<string> = await axios.get('https://www.baidu.com')
    console.log('end', response.data)
    // 这个 toast 无法显示
    XTEasyHUD.showToast('请求完成')
  }
}

@Entry
@Component
struct Index {
  vm: viewModel = new viewModel()
  build() {
    Column() {
      Button('异步显示 Toast')
        .onClick(() => {
          this.vm.asyncShowToast()
        })
    }
    .height('100%')
    .width('100%')
  }
}

我在该组件库的文档中,有做该问题的特别说明和解决方案描述:[已知问题特别注意]

解决方案:

import axios, { AxiosResponse } from '@ohos/axios'
import {
  XTEasyHUD
} from '@jxt/xt_hud'

class viewModel {
  async asyncShowToast() {
    let response: AxiosResponse<string> = await axios.get('https://www.baidu.com')
    console.log('end', response.data)
    XTEasyHUD.showToast('请求完成')
  }
}

@Entry
@Component
struct Index {
  vm: viewModel = new viewModel()

  // Warning: 强烈建议在全局根页面组件中事先做一次XTEasyHUD的全局配置,如果使用默认样式,可以直接进行空配置
  // 这样可以保证后续使用时,异步场景中的 HUD 可以正常加载
  aboutToAppear(): void {
    XTEasyHUD.globalConfigToast()
    XTEasyHUD.globalConfigLoading()
    XTEasyHUD.globalConfigProgress()
  }

  build() {
    Column() {
      Button('异步显示 Toast')
        .onClick(() => {
          this.vm.asyncShowToast()
        })
    }
    .height('100%')
    .width('100%')
  }
}

这个本质做的是,在 UI 组件环境中,执行了 HUD 组件的预初始化,避免后续执行 HUD 显示时(此时 HUD 可能还未初始化,组件库内部逻辑是懒加载的)的 UI 上下文获取异常。

2. 更优雅的方案:runScopedTask

其实 ArkUI 框架中有对应的 UIContext 回溯方法:[runScopedTask]

在系统很多 API 的执行过程中,该方法都很有用:

  1. [DisplaySync.start():start接口是将DisplaySync关联到UI实例和窗口,若在非UI页面中或者一些异步回调中进行start操作,可能无法跟踪到当前UI的上下文,导致start接口失败,会进一步导致订阅函数无法执行]
  2. [Environment和UIContext相关联]
import {
  XTEasyHUD
} from '@jxt/xt_hud'
import { window } from '@kit.ArkUI'

class viewModel {
  async asyncShowToast() {
    let response: AxiosResponse<string> = await axios.get('https://www.baidu.com')
    console.log('end', response.data)
    // 回溯 UI 上下文
    let windowClass = await window.getLastWindow(getContext())
    let uiContext = windowClass.getUIContext()
    uiContext.runScopedTask(() => {
      XTEasyHUD.showToast('请求完成')
    })
  }
}

@Entry
@Component
struct Index {
  vm: viewModel = new viewModel()

  build() {
    Column() {
      Button('异步显示 Toast')
        .onClick(() => {
          this.vm.asyncShowToast()
        })
    }
    .height('100%')
    .width('100%')
  }
}

更好的方式,自然是我在我的组件库内部逻辑中,做好对应的 UI 上下文回溯操作:

static async showToast(text: string, options?: XTHUDToastOptions) {
  if (!(text.length > 0)) {
    return
  }
  // 懒加载
  await _EasyHUDManager.initXTEasyHUDToast(null)
  _EasyHUDManager.showToast(text, options)
}

async initXTEasyHUDToast(globalOptions?: ((options: XTHUDToastOptions) => void) | null) {
  if (!_XTEasyHUDManager._toast) {
    // 在 UI 上下文环境中,执行 HUD 组件初始化
    let windowClass = await window.getLastWindow(getContext())
    let uiContext = windowClass.getUIContext()
    uiContext.runScopedTask(() => {
      _XTEasyHUDManager._toast = new XTEasyHUDToast(undefined, {
        globalOptions: globalOptions
      })
      _XTEasyHUDManager._toast.mounted()
    })
  }
}

但这样操作有很大的弊端:

首先,因为getLastWindow操作是异步的,会导致整体函数变为异步操作,破坏了整体 API 的执行时序和封装;其次,getContext()操作并未传入任何组件(可选入参),也就是该上下文获取操作,很可能会执行失败,导致后续runScopedTask回溯失败。

实测在 Ability 启动阶段,如果强制执行上述操作,可能会导致同样的异常问题,这个依旧算不上安全。

3. 最佳实践

如果想在任意环境中构建 UI 组件,最好的方案,还是使用 [ComponentContent]。

ComponentContent 在实例化时,需要显示的传入 UIContext,至于如何获取 UIContext,那就是另一个问题了。

let contentNode = new ComponentContent(uiContext, wrapBuilder(buildText), new Params(this.message));

我在我的组件库 V3 版本中新增的 [XTPromptHUD],就是利用 ComponentContent 做的,且内置了一套相对完善的 UI 上下文自动获取逻辑,依旧可以做到一句话执行显示 HUD 的操作,但相对合理和安全的,还是用户在使用前自定义传入 UIContext。

/// 异步获取context
private static asyncGetUIContext(callback: (uiContext: UIContext | null) => void) {
  let context = getContext()
  if (context) {
    window.getLastWindow(context).then((windowClass: window.Window) => {
      let uiContext = windowClass.getUIContext()
      if (callback) {
        callback(uiContext)
      }
    }).catch(() => {
      if (callback) {
        callback(null)
      }
    })
  } else {
    if (callback) {
      callback(null)
    }
  }
}

/// 异步自动初始化 toast
private static asyncConfigToast(callback: (toast: XTPromptHUDToastClass | null) => void) {
  XTPromptHUD.asyncGetUIContext((uiContext: UIContext | null) => {
    if (uiContext) {
      let toastHUD = XTPromptHUD.initToastInstance(uiContext)
      if (callback) {
        callback(toastHUD)
      }
    } else {
      if (callback) {
        callback(null)
      }
    }
  })
}

static showToast(text: string, options?: XTHUDToastOptions): void {
  if (!(text.length > 0)) {
    return
  }
  if (XTPromptHUD._toast) {
    XTPromptHUD._toast.showToast(text, options)
  } else {
    XTPromptHUD.asyncConfigToast((toast: XTPromptHUDToastClass | null) => {
      if (toast) {
        console.warn('[XTPromptHUD.showToast] warning: globalConfigToast is not executed, the default context is used!')
        toast.showToast(text, options)
      } else {
        console.error('[XTPromptHUD.showToast] error: globalConfigToast must be executed first!')
      // throw new Error('globalConfigToast must be executed first!')
      }
    })
  }
}


最后呢,很多开发朋友不知道需要学习那些鸿蒙技术?鸿蒙开发岗位需要掌握那些核心技术点?为此鸿蒙的开发学习必须要系统性的进行。

而网上有关鸿蒙的开发资料非常的少,假如你想学好鸿蒙的应用开发与系统底层开发。你可以参考这份资料,少走很多弯路,节省没必要的麻烦。由两位前阿里高级研发工程师联合打造的《鸿蒙NEXT星河版OpenHarmony开发文档》里面内容包含了(ArkTS、ArkUI开发组件、Stage模型、多端部署、分布式应用开发、音频、视频、WebGL、OpenHarmony多媒体技术、Napi组件、OpenHarmony内核、Harmony南向开发、鸿蒙项目实战等等)鸿蒙(Harmony NEXT)技术知识点

如果你是一名Android、Java、前端等等开发人员,想要转入鸿蒙方向发展。可以直接领取这份资料辅助你的学习。下面是鸿蒙开发的学习路线图。

​​​​1

高清完整版请点击《鸿蒙NEXT星河版开发学习文档》

针对鸿蒙成长路线打造的鸿蒙学习文档。话不多说,我们直接看详细资料鸿蒙(OpenHarmony )学习手册(共计1236页)与鸿蒙(OpenHarmony )开发入门教学视频,帮助大家在技术的道路上更进一步。

《鸿蒙 (OpenHarmony)开发学习视频》

《鸿蒙生态应用开发V2.0白皮书》

《鸿蒙 (OpenHarmony)开发基础到实战手册》

《鸿蒙开发基础》

《鸿蒙开发进阶》

《鸿蒙开发实战》
在这里插入图片描述

获取这份鸿蒙星河版学习资料,请点击→《鸿蒙NEXT星河版开发学习文档》

总结

鸿蒙—作为国家主力推送的国产操作系统。部分的高校已经取消了安卓课程,从而开设鸿蒙课程;企业纷纷跟进启动了鸿蒙研发。

并且鸿蒙是完全具备无与伦比的机遇和潜力的;预计到年底将有 5,000 款的应用完成原生鸿蒙开发,未来将会支持 50 万款的应用。那么这么多的应用需要开发,也就意味着需要有更多的鸿蒙人才。鸿蒙开发工程师也将会迎来爆发式的增长,学习鸿蒙势在必行!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值