HarmonyOS 鸿蒙Next单例中存在上下文 线程中获取不到上下文 单例无法使用

发布于 1周前 作者 wuwangju 来自 鸿蒙OS

HarmonyOS 鸿蒙Next单例中存在上下文 线程中获取不到上下文 单例无法使用 下面是我向华为提的单,我定义了一个用户持久化的类,需要传入上下文才能够获取单例。但是线程拿不到UI主线程的上下文,有大神有办法解决吗?不行的话我得改好多代码,看起来鸿蒙的多并发模型是封闭独立于JS引擎层的。

这是我的提单:
您好,我在android代码迁移到鸿蒙代码的过程中,定义了一个全局单例,单例中实现了用户持久化保存用户ID的方法,此单例必须传入上下文才能够获取实例。在worker线程中,由于worker线程获取不到UI主线程的context,导致我们无法在线程中使用这个单例,我们发现程序不报错但是阻塞在线程获取context的步骤,我们尝试过GlobalContext的方式,均无用,我们注意到文档中

  1. 当前支持序列化传输的Native绑定对象主要包含:ContextRemoteObject,但是我们没有native的开发经验 这部分文档没有序列化传输context的demo,这种方案可行吗?

  2. 还有我们注意到后续beta版本推出的@Sendable 这个装饰器后续支持的对象引用是否能够向其他线程传入上下文呢?


更多关于HarmonyOS 鸿蒙Next单例中存在上下文 线程中获取不到上下文 单例无法使用的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html

11 回复

试试globalThis呢?

更多关于HarmonyOS 鸿蒙Next单例中存在上下文 线程中获取不到上下文 单例无法使用的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


新的API已经停了。我用了官方demo里的GlobalContext还是不行。 包括我把类构造函数接收context->类构造函数直接接收this.mPreferences仍然不行。我想是因为链入了context阻塞在寻找context的内存地址了。

if (this.mPreferences === undefined) {
  this.mPreferences = preferences.getPreferencesSync(this.mContext, this.options);
}

GlobalContext

// @Sendable
export class GlobalContext {
  private constructor() {}
  private static instance: GlobalContext;
  private _objects = new Map<string, Object>();

  public static getContext(): GlobalContext {
    if (!GlobalContext.instance) {
      GlobalContext.instance = new GlobalContext();
    }
    return GlobalContext.instance;
  }

  getObject(value: string): Object | undefined {
    return this._objects.get(value);
  }

  setObject(key: string, objectClass: Object): void {
    this._objects.set(key, objectClass);
  }
}

有要学HarmonyOS AI的同学吗,联系我:https://www.itying.com/goods-1206.html

你这个代码解决了我的问题。

谢谢。

传context在安卓中是常用的招儿,鸿蒙还没试过,你也可以在那个持久类中声明一个

context: UIAbilityContext; 试试,初始化时看有没可能传过去,纯属探索,反正试试不会烧电脑:)

有要学HarmonyOS AI的同学吗,联系我:https://www.itying.com/goods-1206.html

解决了 确实能传 但是要注意。原先上下文声明我是这么写的:

class A{
mContext: common.UIAbilityContext | null = null;
 public configSDK(context: common.UIAbilityContext): void {
    this.mContext = context;
  };
} 

但是这样我发现我的持久化还是获取不到实例

原:同步获取:

if (this.mPreferences === undefined) {
  this.mPreferences = preferences.getPreferencesSync(this.mContext!, this.options); // 同步
}

改:异步获取:

if (this.mPreferences === undefined) {
  this.mPreferences = await preferences.getPreferences(this.mContext!, this.options); // 异步
}

这样就解决了在线程里获取单例然后再获取用户持久化实例的问题,不过我还是没理解为啥同步不行?因为线程安全机制吗?我是菜鸡我不懂。能跑了 我的代码不用大改了,接下来就是把android共享内存的线程模型想办法迁移到鸿蒙了。

鸿蒙编程中一个巨大的隐藏问题就是以同步思维使用异步方法,出错了都不知道为何,要明白先得转换思维:简单讲就是当你调用现在新的(大多为异步的)API方法时,不能预期执行完你的代码语句就得到结果,所以赋值语句中用个异步方法,预期其返回值可赋值给变量时,这就已经错了,往往得到了空结果,加上await将这个异步方法的返回推迟到真正返回结果时再赋值,则可以得到正确结果,原因非常简单,但是没明白异步方法和同步方法的区别,还用同步的思维去调用异步方法往往就是错得不明不白。

如果用异步编程的思路考虑,用户持久化类的操作也可考虑不在单独线程中执行,直接在UI主线程中执行即可避免此类问题。用线程的担心主要是基于耗时操作阻塞UI线程造成ANR,但异步方法本身已经基本避免这种阻塞的发生,所以放在一个线程中基本影响不大。具体异步后台实现原理不太清楚,但估计UI操作优先级较高,其它耗时操作以队列排序执行,且优先级低于UI相关代码,因此,只要处理代码以异步方式编写,不分线程也不会有之前UI反应迟钝的问题。不知道此持久化操作负载多大,仅个人理解,非官方说明,有错勿喷:)

在HarmonyOS(鸿蒙)系统中,如果单例中存在上下文(Context),但在线程中无法获取到该上下文,导致单例无法使用,这通常是因为上下文与线程的生命周期或作用域不匹配。

鸿蒙系统中的上下文(Context)通常与特定的组件(如Activity、Service等)相关联,这些组件有自己的生命周期。当从单例中尝试访问与某个组件绑定的上下文时,如果该组件已经销毁或尚未创建,上下文将不可用。

在多线程环境中,如果线程尝试访问单例中的上下文,而该上下文实际上是与创建单例时的线程(通常是主线程)绑定的,那么在线程中就可能无法正确获取到该上下文。

解决这类问题的一种方法是确保上下文在需要时是可用的,并且与线程的生命周期相匹配。例如,可以通过以下方式:

  1. 传递上下文:在线程创建时,显式地将所需的上下文作为参数传递给线程。
  2. 使用应用上下文:如果上下文不需要与特定的组件生命周期绑定,可以考虑使用getApplicationContext()获取的应用上下文。
  3. 线程同步:确保在访问上下文时,相关的组件仍然处于活动状态,或者通过适当的同步机制来保护对上下文的访问。

如果问题依旧没法解决请联系官网客服,官网地址是:https://www.itying.com/category-93-b0.html

回到顶部