【成长纪实】ArkTS 中单实例模式和多实例模式的区别
摘要:ArkTS中的UIAbility支持单实例(singleton)和多实例(multiton)两种启动模式。单实例模式下系统只维护一个实例,重复启动会触发onNewWant回调复用现有实例,适合主页面和全局状态管理场景。多实例模式每次启动都会创建新实例,各实例生命周期独立,适合需要并行显示多个相同页面的场景。开发者可在module.json5中通过launchType字段配置启动模式,默认是单
·
ArkTS 中单实例模式和多实例模式的区别
📌 快速概览
在 HarmonyOS ArkTS 中,UIAbility 支持两种启动模式:单实例模式(singleton) 和 多实例模式(multiton)。这两种模式决定了应用在运行时如何管理 UIAbility 实例。
🎯 一、核心概念
1.1 什么是 UIAbility 启动模式?
UIAbility 启动模式:指定 UIAbility 在被启动时如何创建和管理实例的策略。
两种模式:
| 启动模式 | 英文名 | 说明 |
|---|---|---|
| 单实例模式 | singleton | 系统中只存在一个 UIAbility 实例 |
| 多实例模式 | multiton | 每次启动都会创建一个新的 UIAbility 实例 |
| 指定实例模式 | specified | 根据业务需要创建多个命名实例(高级用法) |
注意:本文档主要介绍单实例模式和多实例模式。
1.2 配置位置
在 module.json5 文件中配置:
{
"module": {
"abilities": [
{
"name": "EntryAbility",
"srcEntry": "./ets/entryability/EntryAbility.ets",
"launchType": "singleton", // 或 "multiton"
"description": "$string:EntryAbility_desc",
"icon": "$media:icon",
"label": "$string:EntryAbility_label",
"exported": true
}
]
}
}
关键字段:
launchType: 启动模式"singleton": 单实例模式(默认)"multiton": 多实例模式"specified": 指定实例模式
📖 二、单实例模式(singleton)
2.1 核心特点
定义:系统中只会存在一个 UIAbility 实例。
行为:
- 首次启动:创建新的 UIAbility 实例
- 再次启动:复用已存在的实例,不会创建新实例
- 回调触发:调用
onNewWant()回调,而不是onCreate()
2.2 生命周期流程
首次启动
启动 UIAbility
↓
onCreate() // 创建实例
↓
onWindowStageCreate() // 创建窗口
↓
onForeground() // 进入前台
↓
显示页面
再次启动(已有实例)
启动 UIAbility
↓
onNewWant() // 收到新的启动请求
↓
onForeground() // 进入前台(如果在后台)
↓
显示页面
2.3 代码示例
配置单实例模式
// module.json5
{
"module": {
"abilities": [
{
"name": "MainAbility",
"launchType": "singleton", // 单实例模式
"srcEntry": "./ets/entryability/MainAbility.ets"
}
]
}
}
UIAbility 实现
// MainAbility.ets
import UIAbility from "@ohos.app.ability.UIAbility";
import window from "@ohos.window";
import Want from "@ohos.app.ability.Want";
export default class MainAbility extends UIAbility {
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) {
console.info("[MainAbility] onCreate - 首次创建");
console.info("Want:", JSON.stringify(want));
}
onNewWant(want: Want, launchParam: AbilityConstant.LaunchParam) {
console.info("[MainAbility] onNewWant - 再次启动(复用实例)");
console.info("新的 Want:", JSON.stringify(want));
// 处理新的启动参数
if (want.parameters) {
const params = want.parameters as Record<string, string>;
const page = params.page || "pages/Index";
// 跳转到指定页面
this.context.windowStage
?.getMainWindow()
.then((windowObj: window.Window) => {
windowObj.loadContent(page);
});
}
}
onForeground() {
console.info("[MainAbility] onForeground - 进入前台");
}
onBackground() {
console.info("[MainAbility] onBackground - 进入后台");
}
onDestroy() {
console.info("[MainAbility] onDestroy - 销毁");
}
}
2.4 启动单实例 UIAbility
// 首次启动
import common from "@ohos.app.ability.common";
// 获取 context
let context = getContext(this) as common.UIAbilityContext;
// 启动 UIAbility
context
.startAbility({
bundleName: "com.example.myapp",
abilityName: "MainAbility",
parameters: {
page: "pages/Index",
},
})
.then(() => {
console.info("启动成功");
})
.catch((error: Error) => {
console.error("启动失败:", error.message);
});
// 再次启动(会触发 onNewWant)
context.startAbility({
bundleName: "com.example.myapp",
abilityName: "MainAbility",
parameters: {
page: "pages/Detail",
id: "123",
},
});
2.5 使用场景
✅ 适合场景:
-
主页面
- 应用的入口页面
- 首页、主界面
-
单一功能页面
- 设置页面
- 关于页面
- 帮助页面
-
全局状态管理
- 需要保持全局状态的页面
- 音乐播放器、下载管理器
-
避免重复创建
- 内存占用大的页面
- 需要保持数据连续性的页面
示例:
// 音乐播放器(单实例)
@Entry
@Component
struct MusicPlayer {
@State currentSong: Song = null
@State isPlaying: boolean = false
build() {
Column() {
Text(`正在播放: ${this.currentSong?.name}`)
Row() {
Button('上一曲').onClick(() => this.previous())
Button(this.isPlaying ? '暂停' : '播放').onClick(() => this.togglePlay())
Button('下一曲').onClick(() => this.next())
}
}
}
}
📖 三、多实例模式(multiton)
3.1 核心特点
定义:每次启动都会创建新的 UIAbility 实例。
行为:
- 每次启动:都会创建新的 UIAbility 实例
- 独立生命周期:每个实例有自己独立的生命周期
- 不会调用
onNewWant():每次都调用onCreate()
3.2 生命周期流程
每次启动
启动 UIAbility
↓
onCreate() // 创建新实例
↓
onWindowStageCreate() // 创建窗口
↓
onForeground() // 进入前台
↓
显示页面
多个实例共存
实例 1 实例 2 实例 3
↓ ↓ ↓
onCreate() onCreate() onCreate()
↓ ↓ ↓
onForeground() onForeground() onForeground()
↓ ↓ ↓
显示页面 显示页面 显示页面
3.3 代码示例
配置多实例模式
// module.json5
{
"module": {
"abilities": [
{
"name": "DocumentAbility",
"launchType": "multiton", // 多实例模式
"srcEntry": "./ets/entryability/DocumentAbility.ets"
}
]
}
}
UIAbility 实现
// DocumentAbility.ets
import UIAbility from "@ohos.app.ability.UIAbility";
import window from "@ohos.window";
import Want from "@ohos.app.ability.Want";
export default class DocumentAbility extends UIAbility {
private instanceId: string = "";
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) {
// 每次启动都会调用
this.instanceId = `instance_${Date.now()}`;
console.info(`[DocumentAbility] onCreate - 创建新实例: ${this.instanceId}`);
console.info("Want:", JSON.stringify(want));
// 获取文档 ID
if (want.parameters) {
const params = want.parameters as Record<string, string>;
const docId = params.docId;
console.info(`打开文档: ${docId}`);
}
}
onWindowStageCreate(windowStage: window.WindowStage) {
console.info(`[DocumentAbility] onWindowStageCreate - ${this.instanceId}`);
windowStage.loadContent("pages/DocumentEditor", (err, data) => {
if (err.code) {
console.error("加载页面失败:", err.message);
return;
}
console.info("加载页面成功");
});
}
onForeground() {
console.info(`[DocumentAbility] onForeground - ${this.instanceId}`);
}
onBackground() {
console.info(`[DocumentAbility] onBackground - ${this.instanceId}`);
}
onDestroy() {
console.info(`[DocumentAbility] onDestroy - ${this.instanceId}`);
}
}
3.4 启动多实例 UIAbility
// 启动多个文档编辑器实例
import common from "@ohos.app.ability.common";
let context = getContext(this) as common.UIAbilityContext;
// 打开文档 1
context.startAbility({
bundleName: "com.example.myapp",
abilityName: "DocumentAbility",
parameters: {
docId: "doc_001",
docName: "项目方案.docx",
},
});
// 打开文档 2(创建新实例)
context.startAbility({
bundleName: "com.example.myapp",
abilityName: "DocumentAbility",
parameters: {
docId: "doc_002",
docName: "会议纪要.docx",
},
});
// 打开文档 3(创建新实例)
context.startAbility({
bundleName: "com.example.myapp",
abilityName: "DocumentAbility",
parameters: {
docId: "doc_003",
docName: "技术文档.docx",
},
});
结果:
- 创建了 3 个独立的 DocumentAbility 实例
- 每个实例显示不同的文档
- 用户可以在 3 个文档之间切换
3.5 使用场景
✅ 适合场景:
-
文档编辑器
- 同时打开多个文档
- 每个文档独立编辑
-
浏览器标签页
- 每个标签页是一个实例
- 独立的浏览历史
-
聊天窗口
- 同时和多个好友聊天
- 每个聊天窗口独立
-
多任务处理
- 需要并行处理多个任务
- 每个任务独立管理
示例:
// 文档编辑器(多实例)
@Entry
@Component
struct DocumentEditor {
@State documentId: string = ''
@State content: string = ''
aboutToAppear() {
// 加载文档内容
const params = router.getParams() as Record<string, string>
this.documentId = params.docId
this.loadDocument(this.documentId)
}
loadDocument(docId: string) {
// 从数据库或网络加载文档
console.info(`加载文档: ${docId}`)
}
build() {
Column() {
Text(`文档 ID: ${this.documentId}`)
.fontSize(16)
TextArea({ text: this.content })
.onChange((value: string) => {
this.content = value
})
Row() {
Button('保存').onClick(() => this.save())
Button('关闭').onClick(() => this.close())
}
}
}
save() {
console.info('保存文档')
}
close() {
// 关闭当前实例
const context = getContext(this) as common.UIAbilityContext
context.terminateSelf()
}
}
📊 四、两种模式对比
4.1 核心区别
| 对比项 | 单实例模式(singleton) | 多实例模式(multiton) |
|---|---|---|
| 实例数量 | 只有 1 个 | 可以有多个 |
| 首次启动 | 调用 onCreate() |
调用 onCreate() |
| 再次启动 | 调用 onNewWant() |
调用 onCreate()(新实例) |
| 内存占用 | 较小(只有一个实例) | 较大(多个实例) |
| 数据隔离 | 无(共享同一实例) | 完全隔离(不同实例) |
| 性能 | 启动快(复用实例) | 启动慢(创建新实例) |
| 适用场景 | 主页、设置、全局功能 | 文档编辑、浏览器、聊天窗口 |
| 配置值 | "launchType": "singleton" |
"launchType": "multiton" |
| 默认模式 | ✅ 是(默认) | ❌ 否 |
4.2 生命周期对比
单实例模式
第 1 次启动:
onCreate() → onWindowStageCreate() → onForeground()
第 2 次启动(已有实例):
onNewWant() → onForeground()
第 3 次启动(已有实例):
onNewWant() → onForeground()
多实例模式
第 1 次启动:
实例 1: onCreate() → onWindowStageCreate() → onForeground()
第 2 次启动:
实例 2: onCreate() → onWindowStageCreate() → onForeground()
第 3 次启动:
实例 3: onCreate() → onWindowStageCreate() → onForeground()
4.3 内存和性能对比
| 指标 | 单实例模式 | 多实例模式 |
|---|---|---|
| 内存占用 | 低(1 个实例) | 高(多个实例) |
| 启动速度 | 快(复用实例) | 慢(创建新实例) |
| 切换速度 | 快(无需创建) | 中等(已创建实例) |
| 资源消耗 | 低 | 高 |
| 数据持久性 | 高(实例一直存在) | 低(实例可能被销毁) |
| 并发能力 | 低(只有一个实例) | 高(多个实例并行) |
🎯 五、实际应用场景
5.1 场景 1:主应用(单实例)
需求:应用的主页面,用户总是返回到同一个首页。
配置:
{
"name": "MainAbility",
"launchType": "singleton",
"srcEntry": "./ets/entryability/MainAbility.ets"
}
代码:
// MainAbility.ets
export default class MainAbility extends UIAbility {
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) {
console.info("[MainAbility] onCreate - 应用启动");
}
onNewWant(want: Want, launchParam: AbilityConstant.LaunchParam) {
console.info("[MainAbility] onNewWant - 返回应用");
// 处理启动参数(如通知点击、分享等)
if (want.parameters) {
const params = want.parameters as Record<string, string>;
// 根据参数跳转到不同页面
if (params.action === "notification") {
this.navigateToNotification(params.notificationId);
} else if (params.action === "share") {
this.navigateToShare(params.shareData);
}
}
}
navigateToNotification(notificationId: string) {
// 跳转到通知详情页
router.pushUrl({
url: "pages/NotificationDetail",
params: { id: notificationId },
});
}
navigateToShare(shareData: string) {
// 跳转到分享页面
router.pushUrl({
url: "pages/Share",
params: { data: shareData },
});
}
}
5.2 场景 2:文档编辑器(多实例)
需求:用户可以同时打开多个文档进行编辑。
配置:
{
"name": "DocumentAbility",
"launchType": "multiton",
"srcEntry": "./ets/entryability/DocumentAbility.ets"
}
代码:
// DocumentAbility.ets
export default class DocumentAbility extends UIAbility {
private documentId: string = "";
private documentData: DocumentData | null = null;
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) {
console.info("[DocumentAbility] onCreate - 打开新文档");
// 获取文档 ID
if (want.parameters) {
const params = want.parameters as Record<string, string>;
this.documentId = params.docId || "";
// 加载文档数据
this.loadDocument(this.documentId);
}
}
async loadDocument(docId: string) {
try {
// 从数据库或网络加载文档
const doc = await DocumentService.getDocument(docId);
this.documentData = doc;
console.info(`文档加载成功: ${doc.name}`);
} catch (error) {
console.error("文档加载失败:", error.message);
}
}
onWindowStageCreate(windowStage: window.WindowStage) {
// 加载文档编辑器页面
windowStage.loadContent("pages/DocumentEditor", (err, data) => {
if (err.code) {
console.error("加载页面失败");
return;
}
// 将文档数据传递给页面
AppStorage.SetOrCreate("currentDocument", this.documentData);
});
}
onDestroy() {
console.info(`[DocumentAbility] onDestroy - 关闭文档: ${this.documentId}`);
// 清理资源
this.documentData = null;
}
}
页面代码:
// pages/DocumentEditor.ets
@Entry
@Component
struct DocumentEditor {
@StorageLink('currentDocument') document: DocumentData = null
@State content: string = ''
@State isSaved: boolean = true
aboutToAppear() {
if (this.document) {
this.content = this.document.content
}
}
build() {
Column() {
// 文档标题
Row() {
Text(this.document?.name || '未命名文档')
.fontSize(20)
.fontWeight(FontWeight.Bold)
Text(this.isSaved ? '已保存' : '未保存')
.fontSize(14)
.fontColor(this.isSaved ? Color.Green : Color.Orange)
}
.width('100%')
.justifyContent(FlexAlign.SpaceBetween)
.padding(15)
// 文档内容编辑器
TextArea({ text: this.content })
.width('100%')
.height('80%')
.onChange((value: string) => {
this.content = value
this.isSaved = false
})
// 操作按钮
Row() {
Button('保存')
.onClick(() => this.saveDocument())
Button('另存为')
.onClick(() => this.saveAs())
Button('关闭')
.onClick(() => this.closeDocument())
}
.width('100%')
.justifyContent(FlexAlign.SpaceEvenly)
.padding(15)
}
.width('100%')
.height('100%')
}
async saveDocument() {
try {
await DocumentService.saveDocument(this.document.id, this.content)
this.isSaved = true
promptAction.showToast({ message: '保存成功' })
} catch (error) {
promptAction.showToast({ message: '保存失败' })
}
}
saveAs() {
// 另存为逻辑
console.info('另存为')
}
closeDocument() {
if (!this.isSaved) {
// 提示保存
AlertDialog.show({
title: '提示',
message: '文档未保存,是否保存?',
primaryButton: {
value: '保存',
action: () => {
this.saveDocument().then(() => {
this.terminate()
})
}
},
secondaryButton: {
value: '不保存',
action: () => {
this.terminate()
}
}
})
} else {
this.terminate()
}
}
terminate() {
const context = getContext(this) as common.UIAbilityContext
context.terminateSelf()
}
}
// 文档数据模型
class DocumentData {
id: string
name: string
content: string
createTime: Date
updateTime: Date
constructor(id: string, name: string, content: string) {
this.id = id
this.name = name
this.content = content
this.createTime = new Date()
this.updateTime = new Date()
}
}
// 文档服务(模拟)
class DocumentService {
static async getDocument(docId: string): Promise<DocumentData> {
// 模拟网络请求
return new Promise((resolve) => {
setTimeout(() => {
resolve(new DocumentData(docId, `文档_${docId}`, '这是文档内容...'))
}, 500)
})
}
static async saveDocument(docId: string, content: string): Promise<void> {
// 模拟保存
return new Promise((resolve) => {
setTimeout(() => {
console.info(`保存文档 ${docId}`)
resolve()
}, 300)
})
}
}
5.3 场景 3:浏览器(多实例)
需求:用户可以打开多个浏览器标签页。
配置:
{
"name": "BrowserAbility",
"launchType": "multiton",
"srcEntry": "./ets/entryability/BrowserAbility.ets"
}
代码:
// BrowserAbility.ets
export default class BrowserAbility extends UIAbility {
private tabId: string = ''
private url: string = ''
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) {
this.tabId = `tab_${Date.now()}`
if (want.parameters) {
const params = want.parameters as Record<string, string>
this.url = params.url || 'https://www.example.com'
}
console.info(`[BrowserAbility] 打开新标签页: ${this.tabId}, URL: ${this.url}`)
}
onWindowStageCreate(windowStage: window.WindowStage) {
windowStage.loadContent('pages/BrowserPage', (err, data) => {
if (!err.code) {
// 传递 URL 给页面
AppStorage.SetOrCreate(`tab_${this.tabId}`, this.url)
}
})
}
}
// pages/BrowserPage.ets
@Entry
@Component
struct BrowserPage {
@State currentUrl: string = 'https://www.example.com'
@State canGoBack: boolean = false
@State canGoForward: boolean = false
build() {
Column() {
// 地址栏
Row() {
Button('后退')
.enabled(this.canGoBack)
.onClick(() => this.goBack())
Button('前进')
.enabled(this.canGoForward)
.onClick(() => this.goForward())
TextInput({ text: this.currentUrl })
.layoutWeight(1)
.onSubmit(() => this.navigate(this.currentUrl))
Button('刷新')
.onClick(() => this.refresh())
}
.width('100%')
.padding(10)
// 网页内容
Web({ src: this.currentUrl, controller: this.webController })
.width('100%')
.layoutWeight(1)
.onPageEnd(() => {
this.updateNavigationState()
})
}
.width('100%')
.height('100%')
}
private webController = new WebController()
goBack() {
this.webController.backward()
}
goForward() {
this.webController.forward()
}
refresh() {
this.webController.refresh()
}
navigate(url: string) {
this.webController.loadUrl(url)
}
updateNavigationState() {
this.canGoBack = this.webController.accessBackward()
this.canGoForward = this.webController.accessForward()
this.currentUrl = this.webController.getUrl()
}
}
⚠️ 六、注意事项
6.1 单实例模式注意事项
1. 必须处理 onNewWant()
// ❌ 错误:没有处理 onNewWant
export default class MainAbility extends UIAbility {
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) {
// 首次启动的逻辑
}
// ❌ 缺少 onNewWant,再次启动时无法处理新参数
}
// ✅ 正确:处理 onNewWant
export default class MainAbility extends UIAbility {
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) {
this.handleWant(want);
}
onNewWant(want: Want, launchParam: AbilityConstant.LaunchParam) {
// ✅ 处理再次启动的逻辑
this.handleWant(want);
}
handleWant(want: Want) {
// 统一处理启动参数
if (want.parameters) {
const params = want.parameters as Record<string, string>;
this.navigateToPage(params.page);
}
}
}
2. 状态管理
// 单实例模式下,状态会一直保持
export default class MainAbility extends UIAbility {
private userInfo: UserInfo | null = null;
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) {
// 首次启动时加载用户信息
this.loadUserInfo();
}
onNewWant(want: Want, launchParam: AbilityConstant.LaunchParam) {
// ⚠️ 注意:userInfo 仍然存在,不会重新创建
console.info("用户信息:", this.userInfo);
// 如果需要刷新数据,需要显式调用
if (want.parameters?.refresh === "true") {
this.loadUserInfo();
}
}
async loadUserInfo() {
this.userInfo = await UserService.getUserInfo();
}
}
6.2 多实例模式注意事项
1. 内存管理
// ⚠️ 多实例会占用更多内存
// 需要及时关闭不需要的实例
@Component
struct DocumentEditor {
build() {
Column() {
Button('关闭文档')
.onClick(() => {
// ✅ 关闭当前实例,释放内存
const context = getContext(this) as common.UIAbilityContext
context.terminateSelf()
})
}
}
}
2. 数据隔离
// 每个实例的数据是隔离的
export default class DocumentAbility extends UIAbility {
private documentId: string = ""; // 每个实例独立
private content: string = ""; // 每个实例独立
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) {
// ✅ 每个实例有自己的 documentId 和 content
this.documentId = want.parameters?.docId as string;
this.loadDocument(this.documentId);
}
}
// ⚠️ 如果需要跨实例共享数据,使用 AppStorage 或数据库
AppStorage.SetOrCreate("sharedData", { key: "value" });
3. 实例限制
// ⚠️ 系统对实例数量有限制,不要无限创建实例
// 建议:维护一个实例管理器
class InstanceManager {
private static instances: Set<string> = new Set()
private static MAX_INSTANCES = 5
static canCreateInstance(): boolean {
return this.instances.size < this.MAX_INSTANCES
}
static addInstance(instanceId: string) {
this.instances.add(instanceId)
}
static removeInstance(instanceId: string) {
this.instances.delete(instanceId)
}
}
// 在启动前检查
if (InstanceManager.canCreateInstance()) {
context.startAbility({...})
} else {
promptAction.showToast({ message: '打开的文档数量已达上限' })
}
🎯 七、最佳实践
7.1 选择启动模式的决策树
需要同时存在多个独立实例?
├── 是 → 使用多实例模式(multiton)
│ ├── 文档编辑器
│ ├── 浏览器标签页
│ ├── 聊天窗口
│ └── 多任务处理
│
└── 否 → 使用单实例模式(singleton)
├── 应用主页
├── 设置页面
├── 音乐播放器
└── 全局功能
7.2 性能优化建议
1. 单实例模式
// ✅ 缓存数据,避免重复加载
export default class MainAbility extends UIAbility {
private cachedData: Map<string, any> = new Map();
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) {
this.loadInitialData();
}
onNewWant(want: Want, launchParam: AbilityConstant.LaunchParam) {
// ✅ 使用缓存数据
const params = want.parameters as Record<string, string>;
const page = params.page;
if (this.cachedData.has(page)) {
console.info("使用缓存数据");
this.navigateToPage(page, this.cachedData.get(page));
} else {
console.info("加载新数据");
this.loadPageData(page);
}
}
}
2. 多实例模式
// ✅ 延迟加载,减少启动时间
export default class DocumentAbility extends UIAbility {
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) {
// ✅ 先显示界面,后加载数据
this.showLoadingUI();
// 异步加载数据
this.loadDocumentAsync(want.parameters?.docId as string);
}
async loadDocumentAsync(docId: string) {
try {
const doc = await DocumentService.getDocument(docId);
this.updateUI(doc);
} catch (error) {
this.showError(error.message);
}
}
}
7.3 混合使用
// 应用可以同时使用两种模式
// module.json5
{
"module": {
"abilities": [
{
"name": "MainAbility",
"launchType": "singleton", // 主页面:单实例
"srcEntry": "./ets/entryability/MainAbility.ets"
},
{
"name": "DocumentAbility",
"launchType": "multiton", // 文档编辑:多实例
"srcEntry": "./ets/entryability/DocumentAbility.ets"
},
{
"name": "SettingsAbility",
"launchType": "singleton", // 设置页面:单实例
"srcEntry": "./ets/entryability/SettingsAbility.ets"
}
]
}
}
🎓 八、快速参考
8.1 配置速查
// 单实例模式
{
"name": "MyAbility",
"launchType": "singleton"
}
// 多实例模式
{
"name": "MyAbility",
"launchType": "multiton"
}
8.2 生命周期回调速查
| 回调方法 | 单实例模式 | 多实例模式 | 说明 |
|---|---|---|---|
onCreate() |
首次启动 | 每次启动 | 创建实例 |
onNewWant() |
再次启动 | ❌ 不调用 | 复用实例时调用 |
onWindowStageCreate() |
首次启动 | 每次启动 | 创建窗口 |
onForeground() |
每次前台 | 每次前台 | 进入前台 |
onBackground() |
每次后台 | 每次后台 | 进入后台 |
onDestroy() |
应用退出 | 实例关闭 | 销毁实例 |
8.3 常见问题速查
| 问题 | 解决方案 |
|---|---|
| 如何在单实例中处理新的启动请求? | 实现 onNewWant() 回调 |
| 如何关闭多实例中的某个实例? | 调用 context.terminateSelf() |
| 如何限制多实例的数量? | 维护实例计数器,启动前检查 |
| 如何在实例间共享数据? | 使用 AppStorage 或持久化存储 |
| 如何判断当前使用的是哪种模式? | 查看 module.json5 中的配置 |
📌 九、总结
核心要点
- 单实例模式:系统只有一个实例,适合主页、设置等场景
- 多实例模式:可以创建多个实例,适合文档编辑、浏览器等场景
- 关键区别:单实例会调用
onNewWant(),多实例每次都调用onCreate() - 性能考虑:单实例启动快但灵活性低,多实例灵活但占用内存多
- 混合使用:一个应用可以同时使用两种模式
选择建议
| 场景 | 推荐模式 |
|---|---|
| 应用主页 | 单实例 |
| 设置页面 | 单实例 |
| 音乐播放器 | 单实例 |
| 下载管理器 | 单实例 |
| 文档编辑器 | 多实例 |
| 浏览器标签页 | 多实例 |
| 聊天窗口 | 多实例 |
| 图片查看器 | 多实例 |
记忆口诀
单实例省内存,复用快又稳
多实例能并行,独立又灵活
主页用单例,文档用多例
根据需求选,合理配置好
完! 🚀
更多推荐



所有评论(0)