HarmonyOS开发 - Ability往页面(Pages)中传递数据

打印 上一主题 下一主题

主题 943|帖子 943|积分 2831

       在程序中,页面之间传递数据或数据共享,可以实现页面间的平滑过渡,避免重复加载数据,进步应用的响应速度和流量度;另外,数据传递机制使得页面更容易被重用,可以通过传入不同参数,来适应不同的上下文内容,以及根据需要传递数据,实现按需加载 ,淘汰内存斲丧和进步应用的性能等。
        这篇将通过LocalStorage、EventHub、全局变量,以及Preferences用户首选项等功能,实现Ability向页面(Pages)中传递数据。
一、页面间数据传递

        页面间跳转,可以通过router.push方法跳转到目标页面,并携带参数。代码如下:
  1.   Column() {
  2.         Image($rawfile('u27.png'))
  3.           .width("64vp")
  4.           .height("64vp")
  5.         Text("门店")
  6.           .height("32vp")
  7.           .textAlign(TextAlign.Center)
  8.           .fontSize("16fp")
  9.           .fontWeight(FontWeight.Bold)
  10.   }.onClick(() => {
  11.         console.log('testTag')
  12.         router.pushUrl({
  13.           url: "pages/Stores",
  14.           params: {
  15.                 flag: "test"
  16.           }
  17.         })
  18.   })
复制代码
        进入被分享页面,通过router.getParams(),来获取点击事件中的params带入数据。代码如下:
  1. @Entry
  2. @Component
  3. struct Stores {
  4.   @State productList: Array<StoresType> = [
  5.     { id: 1, name: '门店一', thumb: $rawfile('u62.png'), },
  6.     { id: 2, name: '门店二', thumb: $rawfile('u76.png') }
  7.   ]
  8.   aboutToAppear(){
  9.     const params = router.getParams()
  10.     console.log('testTag', JSON.stringify(params))
  11.   }
  12.   
  13.   // 略...
  14. }
复制代码
        此时控制台输出结果中可以看到,被分享页面获取到了上级页面的params带入参数。如下图:


二、Ability数据传递

        在HarmonyOS中,从Ability向Page页面传递数据可以通过以下几种方式实现:
2.1、LocalStorage

        LocalStorage是页面级的UI状态存储,通过@Entry装饰器吸收的参数可以在页面内共享同一个LocalStorage实例。LocalStorage也可以在UIAbility实例内,在页面间共享状态,也可以通过GetShared接口,实现跨页面、UIAbility实例内共享。
        在一上篇中,已经和各人介绍了使用LocalStorage将数据传递到页面方法,所在:
HarmonyOS开发 - 餐饮APP中多门店多窗口打开实例增补-CSDN博客
        分享数据Ability代码如下:
  1. import UIAbility from '@ohos.app.ability.UIAbility';
  2. import hilog from '@ohos.hilog';
  3. import window from '@ohos.window';
  4. import Want from '@ohos.app.ability.Want';
  5. export default class StoreAbility extends UIAbility {
  6.   // 略...
  7.   onWindowStageCreate(windowStage: window.WindowStage) {
  8.     // Main window is created, set main page for this ability
  9.     hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate');
  10.     hilog.info(0x0000, 'testTag', 'storeName:' + this.launchWant.parameters.storeName);
  11.     // 通过实例new LocalStorage实例将launchWant数据传递到页面中
  12.     windowStage.loadContent('pages/Index', new LocalStorage(this.launchWant.parameters), (err, data) => {
  13.       if (err.code) {
  14.         hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? '');
  15.         return;
  16.       }
  17.       hilog.info(0x0000, 'testTag', 'Succeeded in loading the content. Data: %{public}s', JSON.stringify(data) ?? '');
  18.     });
  19.   }
  20.   // 略...
  21. }
复制代码
        被分享页面中吸收数据,代码如下:
  1. @Entry
  2. @Component
  3. struct Index {
  4.   @State keyword: string = ''
  5.   @State StoreName: string = '-'
  6.   aboutToAppear(){
  7.     const localStorage = LocalStorage.GetShared()
  8.     this.StoreName = localStorage.get('storeName') as string
  9.     console.log('page store name:', this.StoreName)
  10.   }
  11.   // 略...
  12. }
复制代码
        检察控制台输出结果,如下图:

2.2、EventHub

        EventHub提供了Ability组件(UIAbility和ExtensionAbility)的事件机制,以Ability组件为中心提供了订阅、取消订阅和触发事件的数据通信能力。

2.2.1 界说Constants常量 

        在ets/common目录,再创建Constants.ets文件,用于界说和存储开发中使用的常量只读数据。这里在Constants类中界说ABILITY_WANT_DATA常量,用于界说、触发eventHub的事件名。代码如下:
  1. /**
  2. * 常量类
  3. */
  4. export default class Constants {
  5.   // 获取ability 中want数据
  6.   static readonly ABILITY_WANT_DATA: string = 'getAbilityWantData'
  7. }
复制代码
2.2.2 界说eventHub触发事件

        在Ability中onCreate()回调函数中,界说eventHub事件,当使用emit触发事件时,实验该监听事件的回调函数,并获取到onCreate()中的want数据。代码如下:
  1. import UIAbility from '@ohos.app.ability.UIAbility';
  2. import hilog from '@ohos.hilog';
  3. import window from '@ohos.window';
  4. import Want from '@ohos.app.ability.Want';
  5. import Constants from '../common/Constants'
  6. interface Data {
  7.   launchWant: Want;
  8. }
  9. export default class StoreAbility extends UIAbility {
  10.   onCreate(want) {
  11.     hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate');
  12.     this.context.eventHub.on(Constants.ABILITY_WANT_DATA,  (data: Data) => {
  13.       hilog.info(0x0000, 'testTag', 'MainAbility' + JSON.stringify(data));
  14.       data.launchWant = want;
  15.     })
  16.   }
  17.   
  18.   // 略...
  19. }
复制代码
2.2.3 界说getContextWantData函数

        在ets/common目录中,创建util.ets工具包文件,并在内部界说获取数据的方法getContextWantData(),在页面文件实验时通过它获取eventHub事件中的数据。代码如下:
  1. import Want from '@ohos.app.ability.Want'
  2. import hilog from '@ohos.hilog';
  3. import Constants from './Constants'
  4. class EventData {
  5.   launchWant: Want | null = null
  6. }
  7. let that = this;
  8. export function getContextWantData(): Want {
  9.   hilog.info(0x0000, 'testTag', 'Util start')
  10.   let context = getContext(that);
  11.   // 定义数据bus事件
  12.   let data: EventData = new EventData();
  13.   // 触发eventHub事件,请求数据
  14.   context.eventHub.emit(Constants.ABILITY_WANT_DATA, data);
  15.   hilog.info(0x0000, 'testTag', 'Util want ' + JSON.stringify(data.launchWant as Want));
  16.   return data.launchWant as Want;
  17. }
复制代码
2.2.4 页面获取数据

        页面中引入getContextWantData()函数,在struct外部门获取wantData数据,在aboutToAppear()回调函数中输出结果参数并查询获取的结果。
  1. import Header from '../components/Header'
  2. // 略...
  3. import { getContextWantData } from '../common/utils'
  4. const wantData = getContextWantData()
  5. @Entry
  6. @Component
  7. struct Index {
  8.   @State keyword: string = ''
  9.   @State StoreName: string = '-'
  10.   aboutToAppear(){
  11.     const params = wantData.parameters
  12.     this.StoreName = params('storeName')
  13.     console.log('testTag want parameters', JSON.stringify(params))
  14.   }
  15.   
  16.   // 略...
  17. }  
  18.   
复制代码
        使用此方法,同样可以实现数据共享和传递。并且,从下图中可以看出,各自实验的先后顺序。

如上图可知,程序中各自实验流程:

  • Ability中的onCreate()回调函数先实验于页面,所以在触发onCreate()回调函数时,界说eventHub事件和回调函数,等待页面中触发emit事件获取数据。
  • 当加载页面时,实验getContextWantData()函数,触发了emit事件得到了onCreate()中eventHub回调函数响应,并获取回调函数中的want数据,将其通过return返回输出到页面中。
  • 在aboutToAppear()回调函数实验时,将获取到的want数据绑定到当前页面的状态变量StoreName上,使数据向下传递到Header组件中并在界面中显示结果(门店名称)。

2.3、使用全局变量

        可以将数据存储在globalThis对象上,然后在Page页面中直接访问这些数据。这个方法更为直接,且全局共享。
2.3.1 界说GlobalThis类

        首先在ets/common目录中创建globalThis.ets文件,代码如下:
  1. import Want from '@ohos.app.ability.Want'
  2. class GlobalThis {
  3.   launchWant: Want
  4. }
  5. // 单例模式,全局共享
  6. const globalData = new GlobalThis()
  7. export default globalData
复制代码
2.3.2 Ability中绑定

        在Ability中引入globaData实例,并在onCreate()函数实验时,将回调函数中获取到的want数据绑定到globalData实例的launchWant变量上。代码如下:
  1. import UIAbility from '@ohos.app.ability.UIAbility';
  2. import hilog from '@ohos.hilog';
  3. import window from '@ohos.window';
  4. import Want from '@ohos.app.ability.Want';
  5. import globalData from '../common/globalThis'
  6. export default class StoreAbility extends UIAbility {
  7.   onCreate(want) {
  8.     hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate');
  9.     // 获取数据,并绑定在全局变量上
  10.     globalData.launchWant = want;
  11.   }
  12.   
  13.   // 略...
  14. }
复制代码

2.3.3 页面中获取

        在页面中同样是直接引入globalData实例,在aboutToAppear()回调函数实验时绑定门店名称信息,并在控制台输出结果。
  1. import Header from '../components/Header'
  2. // 略...
  3. import globalData from '../common/globalThis'
  4. @Entry
  5. @Component
  6. struct Index {
  7.   @State keyword: string = ''
  8.   @State StoreName: string = '-'
  9.   aboutToAppear(){
  10.     const params = globalData.launchWant.parameters
  11.     this.StoreName = params('storeName')
  12.        
  13.     console.log('testTag globalData launchWant', JSON.stringify(globalData.launchWant.parameters))
  14.   }
复制代码
        控制台输出结果如下图:


2.4、Preferences用户首选项

        通过Preferences用户首选项实现数据持久化,这在之前写过一篇文档中介绍了Preferences用户首选项功能,并使用它封装了一个LocalStorage本地持久化数据功能。
所在1:HarmonyOS开发 - 本地持久化之实现LocalStorage实例_localstorage需要界说吗-CSDN博客
所在2:HarmonyOS开发 - 本地持久化之实现LocalStorage支持多实例-CSDN博客

2.4.1  LocalStorageMulti本地持久化

        这里就直接贴代码了,拷到项目标ets/common目录、命令为localStorageMulti.ets,代码如下:
  1. import common from '@ohos.app.ability.common'
  2. import preferences from '@ohos.data.preferences'
  3. const isJsonObject = (value: string) : boolean => {
  4.   try {
  5.     const parseStr = JSON.parse(value)
  6.     return 'object' === typeof parseStr && null !== parseStr
  7.   } catch (e) {
  8.     console.log('testTag', e)
  9.     return false
  10.   }
  11. }
  12. // 定义存储值类型
  13. type valueType = string | number | boolean
  14. // 定义json对象存储类型
  15. type dataType = { value: valueType | object, expire: number }
  16. /**
  17. * 定义LocalStorage类
  18. */
  19. export class MyLocalStorage {
  20.   private preference: preferences.Preferences // 用户首选项实例对象
  21.   // 定义多Preferences实例 存储变量
  22.   private static multiPreferences: Map<string, MyLocalStorage> = new Map()
  23.   // preferences加载成功回调函数
  24.   public preferenceSuccess: Function = () => {}
  25.   /**
  26.    * 创建多实例
  27.    * @param context
  28.    */
  29.   static multiInstance(context?: common.UIAbilityContext): MyLocalStorage {
  30.     const name = context.abilityInfo.name
  31.     // 如果存在该实例,则直接返回
  32.     if(MyLocalStorage.multiPreferences.has(name)) {
  33.       console.log('testTag context.abilityInfo.name update', name)
  34.       return MyLocalStorage.multiPreferences.get(name)
  35.     }
  36.     // 如果不存在,则创建实例
  37.     else {
  38.       console.log('testTag context.abilityInfo.name create', name)
  39.       const instance = new MyLocalStorage()     // 实例LocalStorage对象
  40.       instance.initial(context)               // 初始化Preferences实例
  41.       // 存储LocalStorage对象
  42.       MyLocalStorage.multiPreferences.set(name, instance)
  43.       // 返回实例对象
  44.       return instance
  45.     }
  46.   }
  47.   // 定义初始化函数
  48.   initial(context: common.UIAbilityContext): void {
  49.     // 这里将UIAbility中应用上下文的name作用为实例名称,即该项目的ApplicationAbility或ProductAbility
  50.     preferences.getPreferences(context, context.abilityInfo.name).then(preference => {
  51.       this.preference = preference
  52.       if('function' === typeof this.preferenceSuccess) this.preferenceSuccess()
  53.       console.log('testTag', 'success~')
  54.     }).catch(e => {
  55.       console.log('testTag error', e)
  56.     })
  57.   }
  58.   /**
  59.    * 定义增加函数
  60.    * @param key
  61.    * @param value
  62.    * @param expire
  63.    */
  64.   put(key: string, value: valueType | object, expire?: Date): void {
  65.     // 定义存储Json格式对象
  66.     const data : dataType = {
  67.       value,      // 存储内容
  68.       expire : (expire ? expire.getTime() : -1)   // 如果失效时间存在,将其转换为时间戳,否则传入-1
  69.     }
  70.     let dataStr: string = '';
  71.     try {
  72.       dataStr = JSON.stringify(data)    // 当数据转换成功,将其存储
  73.       console.log('testTag', dataStr)
  74.     } catch (e) {
  75.       console.log('testTag error', e)
  76.       return
  77.     }
  78.     this.preference.put(key, dataStr).then(() => this.preference.flush()).catch(e => {
  79.       console.log('testTag error', e)
  80.     })
  81.   }
  82.   /**
  83.    * 定义获取对应key数据
  84.    * @param key
  85.    */
  86.   async getValue(key: string): Promise<valueType | object> {
  87.     // 首页判断key值是否存在,不存在返回空
  88.     if(!this.preference.has(key)) {
  89.       return Promise.resolve(null)
  90.     }
  91.     let value = (await this.preference.get(key, '')) as valueType
  92.     // 判断如果为字符串类型数据,并且为JSON对象格式数据,将其转换为对象
  93.     if('string' === typeof value && isJsonObject(value)) {
  94.       try {
  95.         const data: dataType = JSON.parse(value)
  96.         console.log('testTag', data.expire, Date.now(), data.expire < Date.now())
  97.         // 如果当前存储内容无时效性,或者在时效期内,都直接返回
  98.         if(data.expire === -1 || data.expire > Date.now()) {
  99.           return Promise.resolve(data.value)
  100.         }
  101.         // 如果已失效,将其信息删除
  102.         else {
  103.           this.preference.delete(key)
  104.         }
  105.       } catch (e) {
  106.         console.log('testTag error', e)
  107.         return Promise.resolve(null)      // 如果转换出错,返回null
  108.       }
  109.     }
  110.     // 通过Promise异步回调将结果返回(如果内容不为JSON格式对象,或者过了时效期,返回null)
  111.     return Promise.resolve(null)
  112.   }
  113.   /**
  114.    * 更新数据
  115.    * @param key
  116.    * @param value
  117.    */
  118.   async update(key: string, value: valueType){
  119.     try {
  120.       const preValue = await this.getValue(key)
  121.       if(preValue != value) {
  122.         this.put(key, value)
  123.       }
  124.     } catch (e) {
  125.       console.log('testTag error', e)
  126.     }
  127.   }
  128.   /**
  129.    * 定义移除函数
  130.    * @param key
  131.    */
  132.   remove(key: string): void {
  133.     this.preference.delete(key).then(() => this.preference.flush()).catch(e => {
  134.       console.log('testTag error', e)
  135.     })
  136.   }
  137.   /**
  138.    * 定义清除所有数据函数
  139.    */
  140.   clearAll(): void {
  141.     this.preference.clear().then(() => this.preference.flush()).catch(e => {
  142.       console.log('testTag error', e)
  143.     })
  144.   }
  145. }
  146. /**
  147. * 实例LocalStorage
  148. */
  149. const myLocalStorage = new MyLocalStorage()
  150. /**
  151. * 导出localStorage单例对象
  152. */
  153. export default myLocalStorage as MyLocalStorage
复制代码
2.4.2 Ability中初始化并存储数据

        在onCreate()回调函数中,获取MyLocalStorage实例对象,并且等待myStore.preferenceSuccess()实验回调时,表示Preferences实例已加载完成,可以实验存取操作了。代码如下:
  1. import UIAbility from '@ohos.app.ability.UIAbility';
  2. import hilog from '@ohos.hilog';
  3. import window from '@ohos.window';
  4. import Want from '@ohos.app.ability.Want';
  5. import { MyLocalStorage } from '../common/LocalStorageMulti'
  6. export default class StoreAbility extends UIAbility {
  7.   onCreate(want) {
  8.     hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate');
  9.     // 通过本地存储,存储Want数据
  10.     const myStore=  MyLocalStorage.multiInstance(this.context)
  11.     hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate' + JSON.stringify((want.parameters)));
  12.     // 在Preferences首选项加载成功后执行
  13.     myStore.preferenceSuccess = () => {
  14.       myStore.put('want', want.parameters)
  15.     }
  16.   }
  17.   
  18.   // 略...
  19. }
复制代码

2.4.3 页面中获取持久化数据

        在页面中通过MyLocalStorage对象完成want数据获取,首先是将MyLocalStorage实例本地化,方便后续使用,再通过异步完成数据获取工作,并且将结果输出到控制台上。代码如下:
  1. import Header from '../components/Header'
  2. // 略...
  3. import { MyLocalStorage } from '../common/LocalStorageMulti'
  4. import common from '@ohos.app.ability.common'
  5. @Entry
  6. @Component
  7. struct Index {
  8.   @State keyword: string = ''
  9.   @State StoreName: string = '-'
  10.   private myLocalStorage: MyLocalStorage
  11.   async aboutToAppear(){
  12.     this.myLocalStorage = MyLocalStorage.multiInstance(getContext(this) as common.UIAbilityContext)
  13.     // 获取Ability中本地化存储的Want参数信息
  14.     const wantData = await this.myLocalStorage.getValue('want')
  15.     // 将storeName赋值给状态变量
  16.         this.StoreName = wantData.storeName
  17.     console.log('testTag myLocalStorage', JSON.stringify(wantData))
  18.   }
  19.   
  20.   // 略...
  21. }
复制代码
        控制台结果如下图:

        在HarmonyOS中,数据传递和共享的方式多种多样,每种方式都有实在用的场景和上风。选择符合的数据传递和共享方式,可以进步应用的性能、可维护性和用户体验。根据功能场景需求,选择一种较为符合的即可。


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

tsx81428

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表