UIAbility组件与UI的数据同步-使用EventHub进行数据通信

举报
柠檬味拥抱 发表于 2023/12/04 23:17:33 2023/12/04
【摘要】 @[toc] ArkTS应用模型中UIAbility组件与UI的数据同步在基于HarmonyOS的应用模型中,实现UIAbility组件与UI之间的数据同步是关键的开发任务之一。在ArkTS引擎中,可以通过两种主要方式来实现这一目标:使用EventHub和全局对象globalThis。 使用EventHub进行数据通信EventHub提供了一种基于发布订阅模式的事件机制,通过订阅和发布自定义...

@[toc]

ArkTS应用模型中UIAbility组件与UI的数据同步

在基于HarmonyOS的应用模型中,实现UIAbility组件与UI之间的数据同步是关键的开发任务之一。在ArkTS引擎中,可以通过两种主要方式来实现这一目标:使用EventHub和全局对象globalThis。
在这里插入图片描述

使用EventHub进行数据通信

EventHub提供了一种基于发布订阅模式的事件机制,通过订阅和发布自定义事件,实现UIAbility组件/ExtensionAbility组件与UI之间的数据同步。以下是一个使用EventHub的示例:

import UIAbility from '@ohos.app.ability.UIAbility';

const TAG: string = '[Example].[Entry].[EntryAbility]';

export default class EntryAbility extends UIAbility {
    func1(...data) {
        // 处理收到的事件数据
        console.info(TAG, '1. ' + JSON.stringify(data));
    }

    onCreate(want, launch) {
        // 获取eventHub
        let eventhub = this.context.eventHub;
        // 订阅事件
        eventhub.on('event1', this.func1);
        eventhub.on('event1', (...data) => {
            // 处理收到的事件数据
            console.info(TAG, '2. ' + JSON.stringify(data));
        });
    }
}

在UI界面中,通过eventHub.emit()方法触发自定义事件,并根据需要传递参数信息。以下是一个UI界面中触发事件的示例:

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

@Entry
@Component
struct Index {
  private context = getContext(this) as common.UIAbilityContext;

  eventHubFunc() {
    // 触发自定义事件"event1",可以传递参数
    this.context.eventHub.emit('event1');
    this.context.eventHub.emit('event1', 1);
    this.context.eventHub.emit('event1', 2, 'test');
    // 开发者可以根据实际的业务场景设计事件传递的参数
  }

  // 页面展示
  build() {
    // ...
  }
}

在UIAbility的注册事件回调中,可以得到对应的触发事件结果,日志结果会显示收到的事件数据。

使用globalThis进行数据同步

globalThis是ArkTS引擎实例内部的全局对象,可以在引擎内的UIAbility、ExtensionAbility、和Page之间使用,实现数据的同步。以下是一些使用globalThis的示例场景:

1. UIAbility和Page之间使用globalThis

在UIAbility的onCreate生命周期中,可以将数据绑定到globalThis上,然后在对应的UI页面中使用。

import UIAbility from '@ohos.app.ability.UIAbility';

export default class EntryAbility extends UIAbility {
    onCreate(want, launch) {
        globalThis.entryAbilityWant = want;
        // ...
    }

    // ...
}

在UI页面中即可通过globalThis获取到相关数据:

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

@Entry
@Component
struct Index {
  aboutToAppear() {
    let entryAbilityWant = globalThis.entryAbilityWant;
    // 使用获取到的数据
  }

  // 页面展示
  build() {
    // ...
  }
}

2. UIAbility和UIAbility之间使用globalThis

在同一个应用中,可以通过globalThis在不同的UIAbility之间传递数据。

在发送数据的UIAbility:

import UIAbility from '@ohos.app.ability.UIAbility';

export default class AbilityA extends UIAbility {
    onCreate(want, launch) {
        globalThis.entryAbilityStr = 'AbilityA';
        // ...
    }
}

在接收数据的UIAbility:

import UIAbility from '@ohos.app.ability.UIAbility';

export default class AbilityB extends UIAbility {
    onCreate(want, launch) {
        // 获取从AbilityA传递过来的数据
        console.info('Data from AbilityA: ' + globalThis.entryAbilityStr);
        // ...
    }
}

3. 使用globalThis的注意事项

在使用globalThis时,需要注意以下几点:

  • 在Stage模型下,进程内的UIAbility组件共享ArkTS引擎实例,因此需要避免存放相同名称的对象,否则后存放的对象会覆盖先存放的对象。

  • 在FA模型下,每个UIAbility组件之间引擎隔离,不会存在同名对象覆盖的问题。

  • 对于绑定在globalThis上的对象,建议在使用完成后将其赋值为null,以减少对应用内存的占用。

  • 在Stage模型下,同名对象覆盖可能导致数据混乱和错误。在示例中,AbilityB覆盖了AbilityA在globalThis中存放的context,导致后续AbilityA的页面无法正确获取到UIAbilityContext。

通过合理使用EventHub和globalThis,开发者可以实现UIAbility组件与UI之间的数据同步,从而构建更加灵活和响应式的HarmonyOS应用。
在这里插入图片描述

4. 使用globalThis的注意事项

在示例中,有一个场景是在Stage模型下,同名对象覆盖可能导致数据混乱和错误的问题。以下是对该场景的详细说明:

同名对象覆盖导致问题的场景举例

在AbilityA文件中,我们使用globalThis中存放了UIAbilityContext:

import UIAbility from '@ohos.app.ability.UIAbility';

export default class AbilityA extends UIAbility {
    onCreate(want, launch) {
        globalThis.context = this.context; // AbilityA存放context到globalThis
        // ...
    }
}

在AbilityA的页面中,我们获取该UIAbilityContext并进行使用。使用完成后,将AbilityA实例切换至后台:

@Entry
@Component
struct Index {
  onPageShow() {
    let ctx = globalThis.context; // 页面中从globalThis中取出context并使用
    let permissions = ['com.example.permission']
    ctx.requestPermissionsFromUser(permissions, (result) => {
       // ...
    });
  }

  // 页面展示
  build() {
    // ...
  }
}

在AbilityB文件中,我们使用globalThis中存放了UIAbilityContext,并且命名为相同的名称:

import UIAbility from '@ohos.app.ability.UIAbility';

export default class AbilityB extends UIAbility {
    onCreate(want, launch) {
        // AbilityB覆盖了AbilityA在globalThis中存放的context
        globalThis.context = this.context;
        // ...
    }
}

在AbilityB的页面中,我们再次获取该UIAbilityContext并进行使用。此时获取到的globalThis.context表示的是AbilityB中赋值的UIAbilityContext内容:

@Entry
@Component
struct Index {
  onPageShow() {
    let ctx = globalThis.context; // 这时候globalThis中的context是AbilityB的context
    let permissions = ['com.example.permission'];
    ctx.requestPermissionsFromUser(permissions, (result) => { // 使用这个对象就会导致进程崩溃
       console.info('requestPermissionsFromUser result:' + JSON.stringify(result));
    });
  }

  // 页面展示
  build() {
    // ...
  }
}

在AbilityB实例切换至后台后,将AbilityA实例从后台切换回到前台。此时AbilityA的onCreate生命周期不会再次进入:

import UIAbility from '@ohos.app.ability.UIAbility';

export default class AbilityA extends UIAbility {
    onCreate(want, launch) { // AbilityA从后台进入前台,不会再走这个生命周期
        globalThis.context = this.context;
        // ...
    }
}

在AbilityA的页面再次回到前台时,其获取到的globalThis.context表示的为AbilityB的UIAbilityContext,而不是AbilityA的UIAbilityContext。在AbilityA的页面中使用则会出错:

@Entry
@Component
struct Index {
  onPageShow() {
    let ctx = globalThis.context; // 这时候globalThis中的context是AbilityB的context
    let permissions = ['com.example.permission'];
    ctx.requestPermissionsFromUser(permissions, (result) => { // 使用这个对象就会导致进程崩溃
       console.info('requestPermissionsFromUser result:' + JSON.stringify(result));
    });
  }

  // 页面展示
  build() {
    // ...
  }
}

这个例子突显了在Stage模型下,同名对象覆盖可能导致问题的风险。在开发过程中,需要仔细考虑这一点,并采取适当的措施,例如使用不同的命名空间或采用更加安全的数据共享方式。

通过以上细致的使用示例和注意事项,开发者可以更好地理解如何在HarmonyOS应用中使用globalThis进行数据同步,并避免潜在的问题。在实践中,根据具体的应用场景和需求,选择合适的方式进行UIAbility组件与UI的数据同步,从而确保应用的稳定性和可维护性。

5. 使用globalThis的最佳实践

在使用globalThis进行数据同步时,遵循一些最佳实践可以确保代码的可维护性和稳定性。以下是一些建议:

5.1 命名空间

globalThis上创建专门的命名空间,以防止命名冲突。例如,为每个UIAbility组件创建一个独立的命名空间:

import UIAbility from '@ohos.app.ability.UIAbility';

export default class AbilityA extends UIAbility {
    onCreate(want, launch) {
        globalThis.abilityANamespace = {
            context: this.context,
            // 其他需要共享的数据
        };
        // ...
    }
}

在其他UIAbility或UI组件中,使用相应的命名空间来获取数据:

@Entry
@Component
struct Index {
  onPageShow() {
    let ctx = globalThis.abilityANamespace?.context;
    // 使用获取到的数据
  }

  // 页面展示
  build() {
    // ...
  }
}

5.2 生命周期管理

及时释放globalThis上的数据,特别是在UIAbility组件生命周期结束时。避免在不需要数据的时候仍然保存在globalThis上,以减少内存占用。例如,在UIAbility的onDestroy生命周期中进行释放:

import UIAbility from '@ohos.app.ability.UIAbility';

export default class AbilityA extends UIAbility {
    onDestroy() {
        // 释放globalThis上的数据
        globalThis.abilityANamespace = null;
    }
}

5.3 异常处理

在使用globalThis时,要注意异常处理,确保数据的正确性。例如,检查在获取数据之前是否已经设置:

@Entry
@Component
struct Index {
  onPageShow() {
    if (globalThis.abilityANamespace) {
        let ctx = globalThis.abilityANamespace.context;
        // 使用获取到的数据
    } else {
        console.error('Data not available.');
    }
  }

  // 页面展示
  build() {
    // ...
  }
}

6. EventHub与globalThis的选择

在实际应用中,选择使用EventHub还是globalThis取决于具体的需求和场景。以下是一些考虑因素:

6.1 数据规模

如果需要传递的数据规模较小且频繁,使用EventHub可能更为合适。EventHub适用于事件驱动的场景,能够以低耦合的方式进行数据通信。

如果需要传递的数据较大或需要频繁共享的全局数据,globalThis可能更为便利,因为它提供了直接的全局对象。

6.2 生命周期管理

EventHub提供了明确的生命周期管理机制,可以通过off方法取消订阅,以便在不需要时释放资源。这对于长时间运行的应用是一个优势。

globalThis上的数据生命周期与应用程序实例一致,需要在适当的时机手动释放,确保内存使用的合理性。

6.3 耦合度

EventHub通过发布订阅模式实现松耦合,组件之间不直接依赖。这在大型应用中有利于维护和扩展。

globalThis虽然提供了直接的全局访问,但可能增加组件之间的耦合度。在设计良好的应用中,可以通过合理的命名空间和生命周期管理降低耦合。

结语

深入理解ArkTS应用模型中UIAbility组件与UI的数据同步是构建高效、响应式应用的关键一步。通过EventHub和globalThis的灵活使用,可以根据具体场景选择合适的数据同步方式。合理的命名空间、生命周期管理和异常处理有助于确保代码的稳定性和可维护性。在实践中,开发者应该根据具体需求和项目规模做出明智的选择,以提供出色的用户体验。

在这里插入图片描述

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

评论(0

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

全部回复

上滑加载中

设置昵称

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

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

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