Screen Histroy机制

初涉mtk平台,遇到一个奇怪的问题,假如有这样一段代码:(郭金原创,转载请注明出处)

 void EntryFristScreen()

 {

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

  guiBuffer = GetCurrGuiBuffer(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(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(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【#define AddHistory(addHistory) AddHistoryReference(&(addHistory))】这样的调用顺序来分析,我们着重分析一下GenericExitScreen函数,在执行enericExitScreen时,currExitScrnID   = SCR_ID_1;currExitFuncPtr  = NULL;

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

 void GenericExitScreen(U16 scrnID, FuncPtr entryFuncPtr)

 {

        history h;

     U16 nHistory = 0;    

      h.scrnID = scrnID;

      h.entryFuncPtr = entryFuncPtr;

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

     GetCategoryHistory(h.guiBuffer);

      AddHistory(h);     

 }

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

       void GenericExitScreen(currExitScrnID, currEntryFuncPtr)

 {

   history h;

      U16 nHistory = 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中根据现场的全局变量找到对应的Manager Controls,

这里是:

 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(U16 history_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(SCR_ID_1);

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

 SetLeftSoftkeyFunction(EntrySecondScreen, KEY_EVENT_UP);

 SetRightSoftkeyFunction(GoBackHistory, KEY_EVENT_UP);

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

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

      0,  guiBuffer);

}

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

         写到这里,你是不是豁然开朗了?为了能善始善终,我们再来看一下guiBuffer 和inputBuffer的是在哪些时机下释放的,在History模块中,只有static void mmi_free_history_buffer(S16 id)和void DinitHistory(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, FuncPtr in_src_func)

U8 ExecuteRootMainHistoryScreen(void *funcPtr)

当然还有GoBackHistory()

     今天写了第一篇关于工作中分析问题的文章,本来在写文章之前还不是完全清晰History机制保存现场数据guiBuffer 和inputBuffer的机制,经过边写边看,居然发现了它的来龙去脉,看来写文章对完全理解某一问题还是有帮助的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值