Activity 生命周期管理¶
当前实现更新¶
以下说明以当前代码实现为准:
Activity 必须在
egui_activity_init(self, core)时直接绑定目标coreactivity.root_view会在 init 阶段一起绑定到同一个coreegui_activity_start(self, prev_activity)要求self与self.root_view已经属于目标core当前实现不会在启动时自动改写
self->core或root_view的归属关系
bind_core 相关旧接口已经删除,多屏场景下应在构造 Activity 时就传入目标屏幕的 core。
Activity 是 EmbeddedGUI 中管理全屏页面的核心组件,借鉴了 Android Activity 的设计理念。每个 Activity 拥有独立的视图树和完整的生命周期,通过栈式管理实现页面间的前进与回退。
生命周期¶
Activity 的生命周期由 6 个回调函数组成,按顺序依次触发:
onCreate -> onStart -> onResume -> onPause -> onStop -> onDestroy
各状态含义:
状态 |
说明 |
|---|---|
|
Activity 创建,初始化控件和布局,将视图添加到根视图 |
|
Activity 可见,root_view 设为 visible |
|
Activity 获得焦点,允许处理触摸事件 |
|
Activity 失去焦点,禁止处理触摸事件 |
|
Activity 不可见,root_view 设为 hidden |
|
Activity 销毁,从视图树和 Activity 栈中移除 |
状态枚举定义在 egui_activity.h 中:
enum
{
EGUI_ACTIVITY_STATE_NONE = 0,
EGUI_ACTIVITY_STATE_CREATE,
EGUI_ACTIVITY_STATE_START,
EGUI_ACTIVITY_STATE_RESUME,
EGUI_ACTIVITY_STATE_PAUSE,
EGUI_ACTIVITY_STATE_STOP,
EGUI_ACTIVITY_STATE_DESTROY
};
Activity 结构体¶
struct egui_activity
{
egui_dnode_t node; // Activity 栈中的链表节点
uint8_t state; // 当前状态
uint8_t is_need_finish; // 是否需要销毁
egui_core_t *core; // Activity 所属的 core
egui_view_root_group_t root_view; // Activity 的根视图容器
const egui_activity_api_t *api; // 虚函数表
};
虚函数表 egui_activity_api_t 定义了 6 个生命周期回调:
struct egui_activity_api
{
void (*on_create)(egui_activity_t *self);
void (*on_start)(egui_activity_t *self);
void (*on_resume)(egui_activity_t *self);
void (*on_pause)(egui_activity_t *self);
void (*on_stop)(egui_activity_t *self);
void (*on_destroy)(egui_activity_t *self);
};
Activity 栈管理¶
EmbeddedGUI 使用双向链表维护 Activity 栈。核心 API 如下:
// 启动新 Activity(prev_activity 为前一个 Activity,可为 NULL)
void egui_activity_start(egui_activity_t *self, egui_activity_t *prev_activity);
// 结束 Activity(触发 onPause -> onStop -> onDestroy)
void egui_activity_finish(egui_activity_t *self);
// 检查 Activity 是否正处于切换流程中
int egui_activity_check_in_process(egui_activity_t *self);
// 通过子视图查找所属 Activity
egui_activity_t *egui_view_get_activity(egui_view_t *view);
启动流程:调用 egui_activity_start() 时,框架会先 pause 当前 Activity,然后对新 Activity 依次调用 onCreate -> onStart -> onResume。
结束流程:调用 egui_activity_finish() 时,框架标记 is_need_finish,在 onStop 中自动触发 onDestroy,同时恢复前一个 Activity。
切换动画配置¶
Activity 切换支持 4 个动画槽位,分别控制启动和结束时新旧 Activity 的过渡效果:
// 设置启动动画:当前 Activity 的进入动画 + 前一个 Activity 的退出动画
void egui_activity_set_start_anim(
egui_activity_t *self,
egui_animation_t *open_anim, // 当前 Activity 从右侧滑入
egui_animation_t *close_anim // 前一个 Activity 向左侧滑出
);
// 设置结束动画:前一个 Activity 的恢复动画 + 当前 Activity 的退出动画
void egui_activity_set_finish_anim(
egui_activity_t *self,
egui_animation_t *open_anim, // 前一个 Activity 从左侧滑入
egui_animation_t *close_anim // 当前 Activity 向右侧滑出
);
典型的水平滑动切换配置:
// 启动时:新页面从右侧滑入
EGUI_ANIMATION_TRANSLATE_PARAMS_INIT(anim_start_open_param,
EGUI_CONFIG_SCREEN_WIDTH, 0, 0, 0); // from_x, to_x, from_y, to_y
egui_animation_translate_t anim_start_open;
// 启动时:旧页面向左侧滑出
EGUI_ANIMATION_TRANSLATE_PARAMS_INIT(anim_start_close_param,
0, -EGUI_CONFIG_SCREEN_WIDTH, 0, 0);
egui_animation_translate_t anim_start_close;
// 结束时:前一个页面从左侧滑入
EGUI_ANIMATION_TRANSLATE_PARAMS_INIT(anim_finish_open_param,
-EGUI_CONFIG_SCREEN_WIDTH, 0, 0, 0);
egui_animation_translate_t anim_finish_open;
// 结束时:当前页面向右侧滑出
EGUI_ANIMATION_TRANSLATE_PARAMS_INIT(anim_finish_close_param,
0, EGUI_CONFIG_SCREEN_WIDTH, 0, 0);
egui_animation_translate_t anim_finish_close;
如果需要垂直滑动切换,将 x 参数改为 0,y 参数改为 EGUI_CONFIG_SCREEN_HEIGHT 即可。
自定义 Activity¶
自定义 Activity 需要:
定义继承结构体(包含
egui_activity_t base和自定义字段)重写需要的生命周期回调
构建自定义的虚函数表
在 init 函数中调用父类 init 并替换虚函数表
以 HelloActivity 中的 egui_activity_test_t 为例:
// 1. 定义结构体
struct egui_activity_test
{
egui_activity_t base; // 继承基类
int index;
char label_str[20];
egui_view_linearlayout_t layout_1;
egui_view_label_t label_1;
egui_view_button_t button_1; // "Next" 按钮
egui_view_button_t button_2; // "Finish" 按钮
egui_view_button_t button_3; // "Dialog" 按钮
};
// 2. 重写 on_create:初始化控件并添加到 Activity
void egui_activity_test_on_create(egui_activity_t *self)
{
egui_activity_test_t *local = (egui_activity_test_t *)self;
egui_activity_on_create(self); // 调用父类
// 初始化布局和控件...
egui_view_linearlayout_init((egui_view_t *)&local->layout_1, egui_activity_get_core(self));
// ... 设置按钮回调 ...
egui_activity_add_view(self, (egui_view_t *)&local->layout_1);
}
// 3. 构建虚函数表(只替换需要修改的回调)
static const egui_activity_api_t egui_activity_test_t_api_table = {
.on_create = egui_activity_test_on_create, // 自定义
.on_start = egui_activity_on_start, // 使用默认
.on_resume = egui_activity_on_resume,
.on_pause = egui_activity_on_pause,
.on_stop = egui_activity_on_stop,
.on_destroy = egui_activity_test_on_destroy, // 自定义
};
// 4. 初始化函数
void egui_activity_test_init(egui_activity_t *self, egui_core_t *core)
{
egui_activity_init(self, core); // 调用父类 init
self->api = &egui_activity_test_t_api_table; // 替换虚函数表
}
资源管理¶
Activity 应用的资源通过 app_resource_config.json 配置,包括字体和图片。详细说明参见资源管理章节。
HelloActivity 完整流程¶
example/HelloActivity/uicode_disp0.c 展示了完整的 Activity 管理流程:
void uicode_disp0_init(egui_core_t *core)
{
EGUI_UNUSED(core);
// 1. 初始化 Dialog 动画(底部上滑)
egui_animation_translate_init(EGUI_ANIM_OF(&anim_dialog_start));
egui_animation_translate_params_set(&anim_dialog_start, &anim_dialog_start_param);
egui_animation_duration_set(EGUI_ANIM_OF(&anim_dialog_start), 500);
// ... 初始化其他动画 ...
// 2. 初始化 Dialog,并把动画绑定到 Dialog 对象本身
egui_dialog_test_init((egui_dialog_t *)&dialog, core);
egui_dialog_set_anim(
(egui_dialog_t *)&dialog,
EGUI_ANIM_OF(&anim_dialog_start),
EGUI_ANIM_OF(&anim_dialog_finish)
);
// 3. 启动第一个 Activity
// uicode_start_next_activity() 内部会对待启动 Activity 调用:
// egui_activity_set_start_anim(...)
// egui_activity_set_finish_anim(...)
// egui_activity_start(...)
uicode_start_next_activity(NULL);
// 4. 初始化 Toast
egui_toast_std_init((egui_toast_t *)&toast, core);
egui_toast_set_as_default((egui_toast_t *)&toast);
}
Activity 的内存分配支持两种模式:
静态分配:预分配固定数量的 Activity 数组,适合资源受限场景
动态分配:通过
egui_api_malloc动态创建,需在onDestroy中释放
// 静态分配模式
#define ACTIVITY_ARRAY_SIZE 3
static egui_activity_test_t activity_test_array[ACTIVITY_ARRAY_SIZE];
egui_activity_test_t *uicode_get_empty_activity(void)
{
if (activity_index >= ACTIVITY_ARRAY_SIZE)
return NULL;
return &activity_test_array[activity_index++];
}
相关文件¶
src/app/egui_activity.h- Activity 基类定义src/app/egui_activity.c- Activity 基类实现src/core/egui_core.h- Activity 栈管理 APIexample/HelloActivity/- 完整示例
Toast Helper¶
Activity 也提供了基于对象的 Toast 快捷接口:
void egui_activity_show_toast_info(egui_activity_t *self, const char *text);
void egui_activity_show_toast_info_with_duration(egui_activity_t *self, const char *text, uint16_t duration);
典型用法:
static void button_next_click_cb(egui_view_t *self)
{
egui_activity_t *activity = egui_view_get_activity(self);
if (activity != NULL)
{
egui_activity_show_toast_info(activity, "Open next page");
}
}
Core 解析说明¶
当前实现里,egui_activity_start(self, prev_activity) 只使用 self 自身已经绑定的 core。
如果 self 或 self.root_view 不属于传入的目标 core,启动流程会直接返回,不会做自动补绑,也不依赖全局 active core。
egui_activity_show_toast_info(...) /
egui_activity_show_toast_info_with_duration(...) 这类对象式 helper,
则会通过 activity 自身绑定的 core 去查找默认 Toast。
因此只要 Activity 在初始化时已经带上目标屏幕的 core,
后续显示 Toast 时就不需要再额外传 core。
多屏场景下更应该遵守这个约束:创建对象时就明确绑定到目标屏幕的 core,而不是指望启动阶段推断或修正归属关系。