背景: BlackBerry的顯示堆棧(stack): Screen對象在一個一組有序的Screen顯示棧里得到維護(hù)。在棧頂?shù)腟creen對象是顯示給用戶的活動Screen。 當(dāng)應(yīng)用程序顯示一個Screen時,它將這個Screen壓入到棧頂。當(dāng)關(guān)閉一個Screen,將這個Screen從棧里移出,然后顯示棧里的下一個Screen,如果必要會重繪它。 每個Screen在棧里只出現(xiàn)一次。如果同一個Screen壓入到棧不止一次,VM會拋出一個運行時異常。 當(dāng)用戶完成和Screen交互,應(yīng)用程序必須將Screen從棧里移出,以致內(nèi)存不必再用。 不要在同一時間里使用多個Screen,因為每個Screen使用獨立的線程。
問題: 當(dāng)一個BB程序里有很多個screen時,在堆棧里管理維護(hù)它們是一件很困難的事情。 例如,我們在頁面跳轉(zhuǎn),更換screen時,將yigge新的screen壓入棧中。 但也許,某些時候有要回到原來的某個screen。
這個時候,我們不能再壓入同一個screen的相同實例。如前所述,VM會拋出一個運行時異常。 那么,我可以生成同一個screen的一個新的實例,壓入棧頂。這樣可以得到一個新的需要的screen,但是新的剛初始化的。 和那個在棧里的screen并非相同的實例有著不同的數(shù)據(jù)狀態(tài)。
解決: 這里的解決方法是: 1 維持一個對象池(object pool),用于維護(hù)各個screen的實例。 當(dāng)客戶需要一個之前的screen時,對象池給予客戶它維護(hù)著的對應(yīng)的screen實例。 當(dāng)客戶要求的是一個新的頁面的時候,它也能產(chǎn)生新的screen。 在產(chǎn)生新的screen的時候,應(yīng)該用新的screen覆蓋對象池中的維護(hù)的同類的screen舊有實例。 這樣,就可以很靈活地得到一個screen的新的實例,或者得到一個screen之前的實例(用于前一次該頁面的顯示)。
2 而在 BlackBerry 的顯示棧,任何時候只維持棧頂?shù)囊粋€screen。
3 需要顯示某頁時,在 對象池中找到對應(yīng)的的 screen ,壓入到顯示棧。 頁面轉(zhuǎn)換的時候,先將之前的screen從棧中彈出,再壓入新的screen。 net.rim.device.api.ui.UiApplication 是用于管理screen的類。 popScreen(Screen screen) 用于彈出棧頂?shù)膕creen,更新并顯示棧中的下一個screen。 pushScreen(Screen screen) 用于壓入一個screen,更新并顯示這個screen。 net.rim.device.api.ui.Screen 類本身也可以控制自己的彈出。 close() 用于彈出本身,但是有一個附加動作,要是本身是棧中最后一個screen,那么程序也將退出。 這個解決辦法里,棧里只維持一個screen。我們彈出這個screen后棧為空,但我們并不想退出程序,而是想壓入新的screen。 所以,棧操作都由UiApplication來完成。在這個解決辦法里。
實例:
第一次壓入, 因為棧為空無須彈出screen,以后每次壓棧都先彈出棧內(nèi)唯一的screen, 使棧為空再壓入新的screen:
pushScreen( ScreenPool.getBusyScreen( BusyScreen.TYPE_NORMAL ) ); 或者 pushScreen( ScreenPool.getBusyScreen( BusyScreen.TYPE_SYNC) ); 以后每次壓入: UiApplication.getUiApplication().popScreen(); UiApplication.getUiApplication().pushScreen( ScreenPool.getNewIntervListe()); 或者 UiApplication.getUiApplication().popScreen(); UiApplication.getUiApplication().pushScreen( ScreenPool.getPreviousIntervListe()); 或者 UiApplication.getUiApplication().popScreen(); UiApplication.getUiApplication().pushScreen( ScreenPool.getBusyScreen( BusyScreen.TYPE_NORMAL ) );