
回复
作为一个曾因Context使用不当导致内存泄漏的开发者,今天要揭秘HarmonyOS的Context!第一次误用Context导致APP崩溃,现在把这个「应用万能钥匙」的正确用法全公开~
想象你进商场:
类型 | 权限范围 | 类比 |
---|---|---|
AbilityContext | 单个Ability的权限 | 店铺专属通行证 |
ApplicationContext | 全应用的权限 | 商场通用通行证 |
import { UIAbility } from '@ohos.app.ability';
export default class MainAbility extends UIAbility {
onStart() {
// 方法1:直接拿
const context1 = this.context;
// 方法2:通过应用上下文
const context2 = this.getApplicationContext();
console.log(`AbilityContext: ${context1}`);
console.log(`ApplicationContext: ${context2}`);
}
}
import { AbilitySlice } from '@ohos.app.ability';
export class MainSlice extends AbilitySlice {
onPageShow() {
// 从所属Ability拿Context
const context = this.ability.context;
console.log(`Slice中获取的Context: ${context}`);
}
}
import { getContext } from '@ohos.app.ability';
// 自定义组件中获取
const context = getContext(this) as typeof import('@ohos.app.ability').Context;
方法 | 用途 | 示例代码 |
---|---|---|
getFilesDir() | 应用数据目录 | const filesDir = context.getFilesDir(); |
getCacheDir() | 缓存目录(会被清理) | const cacheDir = context.getCacheDir(); |
getEncryptedFilesDir() | 加密目录(存敏感数据) | const encryptedDir = context.getEncryptedFilesDir(); |
// 检查设备是否加密
if (context.isDeviceEncrypted()) {
// 获取加密目录
const encryptedDir = context.getEncryptedFilesDir().path;
// 存敏感数据(如支付信息)
const filePath = `${encryptedDir}/payment_info.json`;
fs.writeFileSync(filePath, JSON.stringify(paymentData));
}
// 订阅事件(在目标组件)
context.eventHub.on('newMessage', (data) => {
console.log(`收到消息:${data}`);
this.updateUI(data);
});
// 发送事件(在发送方)
context.eventHub.publish('newMessage', 'Hello from Context!');
// 存数据(如用户信息)
context.appStorage.put('userInfo', { name: 'HarmonyUser', level: 'VIP' });
// 取数据(在其他组件)
const userInfo = context.appStorage.get('userInfo');
console.log(`用户信息:${userInfo.name}`);
// 存数据(仅当前组件能用)
context.localStorage.put('componentState', { isLoading: false });
// 取数据
const state = context.localStorage.get('componentState');
if (!state.isLoading) {
this.loadData();
}
// 错误示范:长生命周期对象持有短生命周期Context
let badContext: Context;
function wrongWay(abilityContext: AbilityContext) {
badContext = abilityContext; // 危险!Ability销毁后Context泄漏
}
// 正确做法:用ApplicationContext
function rightWay(context: Context) {
// 使用应用级Context,生命周期更长
const appContext = context.getApplicationContext();
}
场景 | 正确Context类型 | 错误类型 | 后果 |
---|---|---|---|
启动新Ability | AbilityContext | ApplicationContext | 部分功能不可用 |
全局数据存储 | ApplicationContext | AbilityContext | 组件销毁后数据丢失 |
export class AppData {
private static _context: Context;
// 存一次,到处用
static init(context: Context) {
this._context = context.getApplicationContext();
}
static get context() {
return this._context;
}
}
// 初始化
AppData.init(context);
// 使用
AppData.context.getFilesDir();
// 不好的写法(每次都取)
for (let i = 0; i < 100; i++) {
const dir = this.context.getFilesDir();
// 操作...
}
// 优化写法(先取一次)
const dir = this.context.getFilesDir();
for (let i = 0; i < 100; i++) {
// 用dir变量
}
android.util.AndroidRuntimeException
记得第一次在自定义View中用Activity的Context,导致Activity销毁后View还持有Context,内存泄漏到APP崩溃~ 现在养成了用ApplicationContext存全局数据的习惯,再也不怕泄漏了~