场景
我们知道在工程中,Ui是一个线程,并且需要一直存在,当我们使用的开机画面在这个线程开启就直接展示的时候,因为awtk的界面是window_open入栈的,即首次打开的窗口会记录在top,往后的窗口会依次往后存放,并记录位置,当跳回主界面的时候,此时调用的window_manager_back_to_home/window_manager_get_top_window会出现开机界面,因此开机画面如果不做回收释放,就会一直存在。
如果要做回收释放,开机界面必须要实现为,可以释放内存的堆结构,并且记录窗口指针,提供外部释放。(同时需要注意一点,window_open调用和释放窗口指针等结构都必须要在ui线程,防止多线程操作死机。)后续在跳回主界面的时候,就会直接回到主界面,而不会回到开机界面,但是当显示是开机界面,如果加入其他界面呢?,就需要采用idle_queue添加主窗口(交互界面中,主窗口为其他窗口的入口)了。
//主窗口某一按键功能,位于ui线程
if (evt->key == TK_KEY_F10) {
window_manager_back_to_home(wm);
//如果没有释放开机界面,回不到主窗口,并且操作会挂掉。
//win = window_manager_get_top_window(wm);
win = widget_child(window_manager(), "win_main");
return_value_if_fail(win != NULL, RET_STOP);
button_win_pages_set(win,FALSE);
return RET_STOP;
}
...
具体更改实现
主线程
//假设主函数有ui线程和work线程。
int main(int argc,char* argv[])
{
thread_start(WinMain(ui线程));
thread_start(work线程);
while(1)
{
delay(1);
}
}
ui线程
int WinMain(void)
{
int lcd_w = 800;
int lcd_h = 480;
#if defined(LCD_W) && defined(LCD_H)
lcd_w = LCD_W;
lcd_h = LCD_H;
#endif
#ifdef WITH_FS_RES
char res_root[MAX_PATH + 1];
char app_root[MAX_PATH + 1];
path_app_root(app_root);
memset(res_root, 0x00, sizeof(res_root));
#if LCD_W == 480
path_build(res_root, MAX_PATH, app_root, "res_480_272", NULL);
#else
path_build(res_root, MAX_PATH, app_root, "res_800_480", NULL);
#endif
tk_init(lcd_w, lcd_h, APP_SIMULATOR, NULL, res_root);
#else
tk_init(lcd_w, lcd_h, APP_SIMULATOR, NULL, NULL);
#endif
#endif
//#define WITH_LCD_PORTRAIT 1
#if defined(USE_GUI_MAIN) && defined(WITH_LCD_PORTRAIT)
if (lcd_w > lcd_h) {
tk_set_lcd_orientation(LCD_ORIENTATION_90);
}
#endif /*WITH_LCD_PORTRAIT*/
#ifdef WITH_LCD_LANDSCAPE
if (lcd_w < lcd_h) {
tk_set_lcd_orientation(LCD_ORIENTATION_90);
}
#endif /*WITH_LCD_PORTRAIT*/
/* 初始化资源 */
assets_init();
/*初始化扩展和自定义窗口*/
tk_ext_widgets_init();
custom_widgets_init();
/* 实现UI app应用 即用户界面主入口*/
application_init(); //进入用户的ui界面
_gui_init_done = 1;
/* awtk死循环运行 */
tk_run();
return 0;
}
static void* pwin=NULL;
void setprogress_bar(int progress) //外部触发ui释放窗口内存。
{
if(pwin)
{
close_Swin(pwin);
pwin=NULL;
}
}
ret_t application_init(void) {
#if 1
pwin=awtk_show_start_box(); //只刷新开机界面 ,并记录窗口句柄
return_value_if_fail(awtk_adapter_init() != RET_OK, RET_FAIL);
#else //同时打开开机界面和主界面的方式是不正确的
pwin=awtk_show_start_box();
open_win_application();
return_value_if_fail(awtk_adapter_init() != RET_OK, RET_FAIL);
#endif
return RET_OK;
}
ret_t open_win_application(void) //主窗口是打开其他窗口的入口。
{
common_id_string_tab_init();
open_window_manager(); //管理所有窗口
open_sys_bar();
widget_t* win = window_open("win_main");
return_value_if_fail(win != NULL, RET_FAIL);
common_win_pages_set(win);
button_win_pages_set(win,FALSE);
widget_t* canvas = canvas_widget_create(win,10,180,60 ,48);
widget_on(canvas, EVT_PAINT, on_paint_vgcanvas, NULL);
common_id_fun_tab_foreach(win, win_main_fun_tab, WIN_MAIN_FUN_TAB_SIZE, PM_UPDATE_PARAM);
widget_on(win, EVT_KEY_DOWN, on_win_key_down, win);
widget_foreach(win, init_widget, win);
return RET_OK;
}
static ret_t idle_close_start_box( const idle_info_t* idle )
{
return_value_if_fail( idle != NULL, RET_BAD_PARAMS );
idle_data_t* p_data = (idle_data_t*)( idle->ctx );
if ( p_data && p_data->win ) {
p_data->callfun_b_enter = FALSE;
timer_remove(p_data->timer_id);
window_close( p_data->win ); //释放窗口
win_close_need_free_mem( p_data );
};
return RET_OK;
}
void close_Swin( void* p ) //必须ui线程调用
{
idle_queue( idle_close_start_box, p );
}
//开机界面必须使用堆创建的方式,直接静态界面,直接将界面缓存在内部管理的链表中,
//如果没有提供外部释放接口。在返回top层,开启home界面的时候,显示的就不是主界面,
//而是开机界面。不符合设计。并且此时操作界面按键,会引起死机。
static ret_t idle_show_start_box( const idle_data_t* idle )
{
return_value_if_fail( idle != NULL, RET_BAD_PARAMS );
idle_data_t* p_data = idle;
widget_t* win = window_open( "home" );//win_debug
if ( win == NULL ) {
win_close_need_free_mem( p_data );
return RET_BAD_PARAMS;
}
widget_t* title = widget_get_child( win, 0 );
widget_t* client = widget_get_child( win, 1 );
widget_t* widget = NULL;
p_data->win = win; //记录窗口,供外部释放。
//if ( p_data->dis_type == MSGBOX_DIS_DELAY ) {
widget = widget_get_child( client, 1 );
widget_set_visible( widget, FALSE, TRUE );
widget = widget_get_child( client, 2 );
widget_set_visible( widget, FALSE, TRUE );
p_data->timer_id = timer_add( on_timer_Sclose_win, p_data, 500 );
//}
return RET_OK;
}
void* awtk_show_start_box()
{
idle_data_t* p = TKMEM_ZALLOC( idle_data_t ); //awtk内部堆申请内存
if(p)
{
wstr_init( &p->text, WSTRLENTH );
wstr_set_utf8( &p->text, "" );
p->info_type = 0;
p->dis_type = 0;
p->callfun = NULL;
p->win = NULL;
idle_show_start_box(p);
}
return p;
}
work线程
uint32_t work线程()
{
//dosomething ......
idle_queue( OnAwtkUiDone, this ); //通过这个接口往ui线程添加主窗口,
//dosomething ......
}
ret_t OnAwtkUiDone( const idle_info_t* idle )
{
CCoreEngine* pCore = (CCoreEngine*)idle->ctx;
if ( pCore )
{
pCore->OnGuiStartDone();
}
return RET_REMOVE;
}
void CCoreEngine::OnGuiStartDone()
{
#if OPEN_AWTK
setprogress_bar(100); //当bar到达100%后,释放开机界面
open_win_application(); //引入主界面
#endif
}