HarmonyOS鸿蒙Next中如何在非UI组件里面使用preferences存取数据?

HarmonyOS鸿蒙Next中如何在非UI组件里面使用preferences存取数据? 想在非UI组件中使用首选项preferences 保存数据,但是使用preference需要获取context,而在非UI组件中没办法通过getIUContext方法获取context对象。

4 回复

解决方案

方案一:通过 AppStorage 传递 Context

在应用启动时将 Context 存储到 AppStorage,然后在非 UI 组件中获取。

// 1. 在 EntryAbility 中存储 Context

 export default class EntryAbility extends UIAbility {

   onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) {

     // 存储 applicationContext 到 AppStorage

     AppStorage.setOrCreate('applicationContext', this.context.getApplicationContext());

     // 或者存储 ability context

     AppStorage.setOrCreate('abilityContext', this.context);

   }

   onWindowStageCreate(windowStage: window.WindowStage) {

     windowStage.loadContent('pages/Index', (err) => {

       if (err.code) {

         return;

       }

     });

   }

 }

 // 2. 在非 UI 组件中获取 Context 并使用 Preferences

 import { preferences } from '@kit.ArkData';

 import { common } from '@kit.AbilityKit';

 export class PreferencesManager {

   private static preferencesInstance: preferences.Preferences | null = null;

   private static readonly PREFERENCES_NAME = 'myPreferences';

   // 初始化 Preferences

   public static async init(): Promise<void> {

     try {

       // 从 AppStorage 获取 context

       let context = AppStorage.get('applicationContext') as common.ApplicationContext;

       if (!context) {

         console.error('Context not found in AppStorage');

         return;

       }

       // 获取 Preferences 实例

       this.preferencesInstance = await preferences.getPreferences(

         context,

         this.PREFERENCES_NAME

       );

       console.info('Preferences initialized successfully');

     } catch (err) {

       console.error(`Failed to init preferences: ${err}`);

     }

   }

   // 保存数据

   public static async put(key: string, value: preferences.ValueType): Promise<void> {

     if (!this.preferencesInstance) {

       await this.init();

     }

     try {

       await this.preferencesInstance?.put(key, value);

       await this.preferencesInstance?.flush();

       console.info(`Data saved: ${key} = ${value}`);

     } catch (err) {

       console.error(`Failed to put data: ${err}`);

     }

   }

   // 获取数据

   public static async get(key: string, defaultValue: preferences.ValueType): Promise<preferences.ValueType> {

     if (!this.preferencesInstance) {

       await this.init();

     }

     try {

       let value = await this.preferencesInstance?.get(key, defaultValue);

       return value ?? defaultValue;

     } catch (err) {

       console.error(`Failed to get data: ${err}`);

       return defaultValue;

     }

   }

   // 删除数据

   public static async delete(key: string): Promise<void> {

     if (!this.preferencesInstance) {

       await this.init();

     }

     try {

       await this.preferencesInstance?.delete(key);

       await this.preferencesInstance?.flush();

       console.info(`Data deleted: ${key}`);

     } catch (err) {

       console.error(`Failed to delete data: ${err}`);

     }

   }

   // 清空所有数据

   public static async clear(): Promise<void> {

     if (!this.preferencesInstance) {

       await this.init();

     }

     try {

       await this.preferencesInstance?.clear();

       await this.preferencesInstance?.flush();

       console.info('All data cleared');

     } catch (err) {

       console.error(`Failed to clear data: ${err}`);

     }

   }

 }

方案二:使用单例模式的 Context 管理器

创建一个专门的 Context 管理类:

// ContextManager.ts

 import { common } from '@kit.AbilityKit';

 export class ContextManager {

   private static instance: ContextManager;

   private applicationContext: common.ApplicationContext | null = null;

   private abilityContext: common.UIAbilityContext | null = null;

   private constructor() {}

   public static getInstance(): ContextManager {

     if (!ContextManager.instance) {

       ContextManager.instance = new ContextManager();

     }

     return ContextManager.instance;

   }

   // 设置 ApplicationContext

   public setApplicationContext(context: common.ApplicationContext): void {

     this.applicationContext = context;

   }

   // 设置 AbilityContext

   public setAbilityContext(context: common.UIAbilityContext): void {

     this.abilityContext = context;

   }

   // 获取 ApplicationContext

   public getApplicationContext(): common.ApplicationContext | null {

     return this.applicationContext;

   }

   // 获取 AbilityContext

   public getAbilityContext(): common.UIAbilityContext | null {

     return this.abilityContext;

   }

 }

 // 在 EntryAbility 中初始化

 export default class EntryAbility extends UIAbility {

   onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) {

     ContextManager.getInstance().setApplicationContext(

       this.context.getApplicationContext()

     );

     ContextManager.getInstance().setAbilityContext(this.context);

   }

 }

 // 在非 UI 组件中使用

 import { preferences } from '@kit.ArkData';

 import { ContextManager } from './ContextManager';

 export class DataService {

   public static async saveData(key: string, value: string): Promise<void> {

     let context = ContextManager.getInstance().getApplicationContext();

     if (!context) {

       console.error('Context not available');

       return;

     }

     try {

       let prefs = await preferences.getPreferences(context, 'myPreferences');

       await prefs.put(key, value);

       await prefs.flush();

     } catch (err) {

       console.error(`Failed to save data: ${err}`);

     }

   }

 }

方案三:通过参数传递 Context

如果非 UI 组件是从 UI 组件调用的,可以直接传递 Context:

// 非 UI 组件

 export class StorageHelper {

   private context: common.Context;

   constructor(context: common.Context) {

     this.context = context;

   }

   public async saveUserInfo(username: string, age: number): Promise<void> {

     try {

       let prefs = await preferences.getPreferences(this.context, 'userPrefs');

       await prefs.put('username', username);

       await prefs.put('age', age);

       await prefs.flush();

     } catch (err) {

       console.error(`Failed to save user info: ${err}`);

     }

   }

   public async getUserInfo(): Promise<{ username: string; age: number }> {

     try {

       let prefs = await preferences.getPreferences(this.context, 'userPrefs');

       let username = await prefs.get('username', '') as string;

       let age = await prefs.get('age', 0) as number;

       return { username, age };

     } catch (err) {

       console.error(`Failed to get user info: ${err}`);

       return { username: '', age: 0 };

     }

   }

 }

 // 在 UI 组件中使用

 @Entry

 @Component

 struct Index {

   private storageHelper: StorageHelper | null = null;

   aboutToAppear() {

     // 通过 getContext 获取 context 并传递

     this.storageHelper = new StorageHelper(getContext(this));

   }

   build() {

     Column() {

       Button('保存数据')

         .onClick(async () => {

           await this.storageHelper?.saveUserInfo('张三', 25);

         })

       Button('读取数据')

         .onClick(async () => {

           let userInfo = await this.storageHelper?.getUserInfo();

           console.info(`User: ${userInfo?.username}, Age: ${userInfo?.age}`);

         })

     }

   }

 }

方案四:使用 GlobalContext(适用于全局单例)

// GlobalContext.ts

 export class GlobalContext {

   private static instance: GlobalContext;

   private objects = new Map<string, Object>();

   private constructor() {}

   public static getInstance(): GlobalContext {

     if (!GlobalContext.instance) {

       GlobalContext.instance = new GlobalContext();

     }

     return GlobalContext.instance;

   }

   public setObject(key: string, obj: Object): void {

     this.objects.set(key, obj);

   }

   public getObject(key: string): Object | undefined {

     return this.objects.get(key);

   }

 }

 // 在 EntryAbility 中设置

 export default class EntryAbility extends UIAbility {

   onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) {

     GlobalContext.getInstance().setObject('context', this.context);

   }

 }

 // 在非 UI 组件中使用

 import { preferences } from '@kit.ArkData';

 import { common } from '@kit.AbilityKit';

 import { GlobalContext } from './GlobalContext';

 export class PreferenceUtil {

   public static async saveData(key: string, value: preferences.ValueType): Promise<void> {

     let context = GlobalContext.getInstance().getObject('context') as common.UIAbilityContext;

     if (!context) {

       console.error('Context not found');

       return;

     }

     try {

       let prefs = await preferences.getPreferences(context, 'myStore');

       await prefs.put(key, value);

       await prefs.flush();

     } catch (err) {

       console.error(`Failed to save data: ${err}`);

     }

   }

 }

完整使用示例

// 1. 在应用启动时初始化(EntryAbility.ets)

 export default class EntryAbility extends UIAbility {

   onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) {

     AppStorage.setOrCreate('applicationContext', this.context.getApplicationContext());

   }

   async onWindowStageCreate(windowStage: window.WindowStage) {

     // 初始化 PreferencesManager

     await PreferencesManager.init();

     windowStage.loadContent('pages/Index', (err) => {

       // ...

     });

   }

 }

 // 2. 在任意非 UI 组件中使用

 export class UserService {

   public static async login(username: string, password: string): Promise<boolean> {

     // 模拟登录逻辑

     if (username && password) {

       // 保存登录状态

       await PreferencesManager.put('isLoggedIn', true);

       await PreferencesManager.put('username', username);

       await PreferencesManager.put('loginTime', Date.now());

       return true;

     }

     return false;

   }

   public static async logout(): Promise<void> {

     await PreferencesManager.put('isLoggedIn', false);

     await PreferencesManager.delete('username');

   }

   public static async isLoggedIn(): Promise<boolean> {

     let isLoggedIn = await PreferencesManager.get('isLoggedIn', false);

     return isLoggedIn as boolean;

   }

 }

更多关于HarmonyOS鸿蒙Next中如何在非UI组件里面使用preferences存取数据?的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


1、可以先将preference相关接口封装成一个工具类。示例如下:

import { preferences } from "@kit.ArkData";

export class StoreUtil {

  private tokenStore?: preferences.Preferences;

  private context: Context;

  private static STORE_UTIL: StoreUtil;

  constructor(context: Context) {

    this.context = context;

  }

  public static getInstance(context: Context): StoreUtil {

    if (!StoreUtil.STORE_UTIL ) {

      StoreUtil.STORE_UTIL = new StoreUtil(context);

    }

    return StoreUtil.STORE_UTIL;

  }

  public async initStore(): Promise<void> {

    try {

      this.tokenStore = await preferences.getPreferences(this.context, 'TokenStore');

    } catch (e) {

      console.error(`initStore fail:${JSON.stringify(e)}`);

    }

  }

  public async putData(key: string, value: string): Promise<void> {

    try {

       if (!this.tokenStore) {

         await this.initStore();

       }

       this.tokenStore?.put(key,value);

    } catch (e) {

      console.error(`putData fail:${JSON.stringify(e)}`);

    }

  }

  public async getData(key: string): Promise<string> {

    let result: string  = '';

    try {

      if (!this.tokenStore) {

        await this.initStore();

      }

      result = await this.tokenStore?.get(key, 'defaultData') as string;

    } catch (e) {

      console.error(`getData fail:${JSON.stringify(e)}`);

    }

    return result;

  }

}

2、创建工具类实例

2.1 在UIAbility的onCreate或者onWindowStageCreate中将context传入工具类中。示例如下:

export default class EntryAbility extends UIAbility {

  ....

  onWindowStageCreate(windowStage: window.WindowStage): void {

    // Main window is created, set main page for this ability

    hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onWindowStageCreate');

    StoreUtil.getInstance(this.context);//创建StoreUtil实例,后面使用preference进行数据

存取时,直接调用工具类接口

    windowStage.loadContent('pages/Index', (err) => {

      if (err.code) {

        hilog.error(DOMAIN, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err));

        return;

      }

      hilog.info(DOMAIN, 'testTag', 'Succeeded in loading the content.');

    });

  }

  .....
}

2.2 或者在UI组件中,通过组件内置方法getUIContext,获取context,实例化工具类。示例如下:

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

import { StoreUtil } from '../common/StoreUtil';

@Entry

@Component

struct Index {

  private storeUtil: StoreUtil = StoreUtil.getInstance(this.getUIContext().getHostContext() as common.UIAbilityContext);

  aboutToAppear(): void {

    this.storeUtil.initStore();

  }

  build() {

    Column({ space: 20 }) {

      Button('PutData')

        .fontSize($r('app.float.page_text_font_size'))

        .fontWeight(FontWeight.Bold)

        .onClick((e: ClickEvent) => {

          this.storeUtil.putData('test', 'TestData001');

        })

      Button('getData')

        .id('HelloWorld')

        .fontSize($r('app.float.page_text_font_size'))

        .fontWeight(FontWeight.Bold)

        .onClick(async (e: ClickEvent) => {

          let result: string = await this.storeUtil.getData('test');

          console.info(`=-=: result from preference:${result}`);

        })

    }

    .height('100%')

    .width('100%')

  }

}

3、在使用preference进行数据存取的地方,可以直接使用该工具类进行操作。

在HarmonyOS Next中,非UI组件使用Preferences存取数据需导入@kit.ArkData模块。通过preferences.getPreferences获取Preferences实例,支持异步或同步方式。使用put方法存储数据,如preferences.put('key', value),再调用flush提交。读取时用get方法,如preferences.get('key', defaultValue)。操作完成后调用close释放资源。确保在EntryAbility或UI上下文外直接调用Preferences API,无需依赖UI组件。

在HarmonyOS Next中,非UI组件(如Service或工具类)可通过全局上下文获取UIContext。使用getContext()方法获取全局Context后,调用getUIAbilityContext()转为UIAbilityContext,即可创建Preferences实例:

import preferences from '@ohos.data.preferences';

// 获取全局上下文并转换为UIAbilityContext
const context = getContext() as common.UIAbilityContext;
const uiAbilityContext = context.getUIAbilityContext();

// 创建Preferences实例
const preferencesName = 'myPrefs';
preferences.getPreferences(uiAbilityContext, preferencesName)
  .then((pref) => {
    // 存取数据
    pref.put('key', 'value').flush();
  });

注意:

  1. 确保在UIAbility或ExtensionAbility上下文中调用
  2. 数据操作需在UI线程执行,非UI线程需通过TaskPool处理
  3. 存取完成后及时调用flush()持久化数据

此方式适用于Service、工具类等非UI组件的数据持久化需求。

回到顶部