MTK Screen Histroy机制

初涉mtk平台,遇到一个奇怪的问题,假如有这样一段代码:

void EntryFristScreen()

{

   EntryNewScreen(SCR_ID_1,NULL, EntryFristScreen, NULL);//第三个参数newEntryHandler不为空

   guiBuffer = GetCurrGuiBuffer_r(SCR_ID_1);

     ........//为了更好的说明问题,省去部分代码和参数

   SetLeftSoftkeyFunction(EntrySecondScreen,KEY_EVENT_UP);

   SetRightSoftkeyFunction(GoBackHistory,KEY_EVENT_UP);

   ShowCategory52Screen(。。, 。。,。。, 

         。。, 。。, 。。,

        。。,。。,。。, 。。, 。。,

 0, guiBuffer); //其中0为设置的列表项高亮度条所在位置

   //问题就在这里,当第一次进入52Screen的时候高亮条在列表项索引0位置,改变高亮条位置之后进入下一屏,再返回,虽然依然是调用EntryFristScreen,虽然ShowCategory52Screen中高亮参数依然是0,但是高亮位置已经不在列表索引0位置

}

为了弄清这个问题和更好的说明Screen的History机制,我们添加一屏,如下:

void EntrySecondScreen()

{

   EntryNewScreen(SCR_ID_2,NULL, EntrySecondScreen, NULL);

   guiBuffer = GetCurrGuiBuffer_r(SCR_ID_2);

   SetLeftSoftkeyFunction(EntryXXXScreen,KEY_EVENT_UP);

   SetRightSoftkeyFunction(GoBackHistory,KEY_EVENT_UP);

   ShowCategoryXXXScreen(。。,。。, 。。, 。。, 。。, 。。,

        。。,。。, 。。, 。。, 。。,

        。。, 。。);

}

        我们要分析的是从第一屏进到第二屏这个动作过程,对于这个过程中发生的任何操作我们只关心对SCR_ID_1和SCR_ID_2的操作,其他的一概不管,首先我们来分析EntryFristScreen中EntryNewScreen(SCR_ID_1, NULL, EntryFristScreen,NULL)所作的操作,在这个操作中除了对SCR_ID_1上一屏的操作我们不管外,这个操作中和

SCR_ID_1相关的操作是:

 currExitScrnID =newscrnID; //即currExitScrnID   =SCR_ID_1;

//currExitScrnID=scrnID; //在SetGenericExitHandler中有一个重复的操作,我们忽略它

currExitFuncPtr=exitFuncPtr;  //即currExitFuncPtr = NULL;

currEntryFuncPtr= entryFuncPtr; //即currEntryFuncPtr =EntryFristScreen

          在EntryNewScreen(SCR_ID_1, NULL, EntryFristScreen,NULL)中与SCR_ID_1相关的重要操作仅有这么多,guiBuffer = GetCurrGuiBuffer_r(SCR_ID_1)操作由于SCR_ID_1并没有被写入historyData栈,所以guiBuffer=NULL,而在ShowCategory52Screen中的层层调用中,我们只需要记住这其中的一个操作,就是对全局函数指针的赋值:

GetCategoryHistory =get_history_function;即GetCategoryHistory   = dm_get_category_history。

          关于第一屏的分析就到这里了,我们即将进入第二屏,在进入第二屏之前,我们先假设它会保存上一屏的参数(高亮度条位置等参数,保存到historyData的Scr栈中的guiBuffer和inputBuffer中),我们先假设这一假设成立,然后再证实它。让我们开始第二屏的分析,同样,在所有的操作过程中,我们只关心SCR_ID_1和SCR_ID_2相关的,并且和主题相关的操作:

         首先,EntryNewScreen(SCR_ID_2, NULL, EntrySecondScreen,NULL)的操作;

以EntryNewScreen->ExecuteCurrExitHandler->ExecuteCurrExitHandler_Ext->GenericExitScreen->AddHistory【#defineAddHistory(addHistory)AddHistoryReference(&(addHistory))】这样的调用顺序来分析,我们着重分析一下GenericExitScreen函数,

在执行GenericExitScreen时,

currExitScrnID   = SCR_ID_1;currExitFuncPtr = NULL;

currEntryFuncPtr =EntryFristScreen;GetCategoryHistory   = dm_get_category_history;这4个变量的值并没有发生改变;因此这段代码

void GenericExitScreen(U16 scrnID, FuncPtrentryFuncPtr)

{

history h;

U16nHistory = 0;   

h.scrnID = scrnID;

h.entryFuncPtr = entryFuncPtr;

mmi_ucs2cpy((S8*)h.inputBuffer, (S8*) &nHistory);//只起一个初始化的作用,把inputBuffer数组置空

GetCategoryHistory_r(h.guiBuffer);

AddHistory(h);    

}

       在ExecuteCurrExitHandler_Ext中调用GenericExitScreen(currExitScrnID,currEntryFuncPtr);相当于:

       void GenericExitScreen(currExitScrnID, currEntryFuncPtr)

{

history h;

U16nHistory = 0;  

h.scrnID = SCR_ID_1;

h.entryFuncPtr = EntryFristScreen;

mmi_ucs2cpy((S8*) h.inputBuffer, (S8*) &nHistory);

dm_get_category_history(h.guiBuffer);

AddHistory(h);  

}

在dm_get_category_history中依据刚才画SCR_ID_1过程中的全局变量(因为SCR_ID_2的画屏操作尚未开始,因此当前的全局变量是记录的是画上一屏的参数或称上下文,保留现场),将这些现场数据保存到h.guiBuffer(对于其他屏,也有保存inputBuffer的过程)中,在dm_get_category_history中根据现场的全局变量找到对应的ManagerControls,

这里是:

case DM_LIST1:

{

   get_list_menu_category_history((U16)p_dm_data->s32CatId, history_buffer);   

   break;

}

在get_list_menu_category_history中将现场的全局变量保存到h.guiBuffer中(这里只用到了guiBuffer),

//这里的history_buffer就是我们传进来的h.guiBuffer

void get_list_menu_category_history (U16history_ID, U8 *history_buffer)

{

   if (history_buffer !=NULL)

   {

U16 hID =(U16) (history_ID | 0x8000); 

list_menu_category_history *h= (list_menu_category_history*)history_buffer; h->history_ID = hID;

   #ifndef__MMI_DICTIONARY__

h->highlighted_item = (S16)MMI_fixed_list_menu.highlighted_item;

h->first_displayed_item= (S16) MMI_fixed_list_menu.first_displayed_item;

h->last_displayed_item= (S16) MMI_fixed_list_menu.last_displayed_item;

h->displayed_items= (S16) MMI_fixed_list_menu.displayed_items;

   #else

h->highlighted_item =    MMI_fixed_list_menu.highlighted_item;

h->first_displayed_item= MMI_fixed_list_menu.first_displayed_item;

h->last_displayed_item= MMI_fixed_list_menu.last_displayed_item;

h->displayed_items= MMI_fixed_list_menu.displayed_items;

#endif

    h->flags= MMI_fixed_list_menu.flags;

    h->state= (S8) (-1);

    h->num_items= MMI_fixed_list_menu.n_items;

   }

}

回到GenericExitScreen函数,在获得现场数据之后调用AddHistory(h),将现场数据添加到Screen的History栈historyData中,History栈中inputBuffer和guiBuffer空间的申请都是在AddHistory也就是AddHistoryReference这个操作中完成的,并用我们用dm_get_category_history得到的现场数据为他赋值:

void AddHistoryReference(history *addHistory)

{

increment();

memset(&historyData[currHistoryIndex],0,sizeof(historyNode)); historyData[currHistoryIndex].scrnID=addHistory->scrnID;

historyData[currHistoryIndex].entryFuncPtr= addHistory->entryFuncPtr;

#ifdef __MMI_UI_SMALL_SCREEN_SUPPORT__

historyData[currHistoryIndex].isSmallScreen =(U16) small_history_node;

#endif

length = mmi_ucs2strlen((PS8)addHistory->inputBuffer);

if (length)

{

 historyData[currHistoryIndex].inputBuffer= OslMalloc(length * ENCODING_LENGTH+            ENCODING_LENGTH);

mmi_ucs2cpy((PS8)historyData[currHistoryIndex].inputBuffer, (PS8)addHistory->inputBuffer); }

historyData[currHistoryIndex].guiBuffer =OslMalloc(MAX_GUI_BUFFER); memcpy(historyData[currHistoryIndex].guiBuffer,addHistory->guiBuffer, MAX_GUI_BUFFER);

}

        到这里我们前面的假设已经得到证明,保存上一屏的现场数据的操作在进入新的一屏前的这一时刻完成,进入新的一屏后在返回上一屏(SCR_ID_1),系统就会从historyData中去读取上一屏(SCR_ID_1)的现场数据。假如依旧是

void EntryFristScreen()

{

EntryNewScreen(SCR_ID_1, NULL,EntryFristScreen, NULL);

guiBuffer = GetCurrGuiBuffer_r(SCR_ID_1);

........//为了更好的说明问题,省去部分代码和参数

SetLeftSoftkeyFunction(EntrySecondScreen,KEY_EVENT_UP);

SetRightSoftkeyFunction(GoBackHistory,KEY_EVENT_UP);

ShowCategory52Screen(。。, 。。, 。。,。。, 。。, 。。,

       。。,。。,。。, 。。, 。。,

       0, guiBuffer);

}

       此时在调用guiBuffer = GetCurrGuiBuffer_r(SCR_ID_1); guiBuffer就不为空了,在ShowCategory52Screen中会通过set_list_menu_category_history(...,guiBuffer)去读取上次退出时的现场数据,而不去理会ShowCategory52Screen中倒数第二个参数(highlighted_item= 0)的赋值情况。所以高亮度条不停留在列表索引0位置。

         写到这里,你是不是豁然开朗了?为了能善始善终,我们再来看一下guiBuffer和inputBuffer的是在哪些时机下释放的,在History模块中,只有static voidmmi_free_history_buffer(S16 id)和voidDinitHistory(void)操作调用了OslMfree(historyData[id].guiBuffer)和OslMfree(historyData[id].inputBuffer);其中DinitHistory是一个全局初始化函数或善后处理函数,即初始化或重新初始化整个History栈;而mmi_free_history_buffer又是一个局部的接口,因此调用它的外部接口就是释放操作的时机,归结起来,在调用一下接口的时候(假如条件满足),会导致inputBuffer和guiBuffer的释放:

U8 DeleteScreens(U16 start_scrnid, U16 end_scrnid)

U8 DeleteBeyondScrTillScr(U16 beyondScrnid, U16 tillScrnid)

U16 DeleteBetweenScreen(U16 StartScrId, U16 EndScrId)

U16 DeleteScreenIfPresent(U16 ScrId)

U16 DeleteScreenFromToNnodes(U16 ScrId, U16 num_nodes)

U8 DeleteFromScrUptoScr(U16 start_scrnid, U16 upto_scrnid)

pBOOL HistoryReplace(U16 out_scrn_id, U16 in_scrn_id, FuncPtrin_src_func)

U8 ExecuteRootMainHistoryScreen(void *funcPtr)

当然还有GoBackHistory()


FORM:http://hi.baidu.com/cwt0408/blog/item/1cfe3b1928af124842a9ad41.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值