歡迎您光臨本站 註冊首頁

探索J2ME應用:如何對記錄進行排序

←手機掃碼閱讀     火星人 @ 2014-03-09 , reply:0

  通過RecordStore類完成了ExpensesApp應用程序的開銷項目的存儲功能.RecordStore類提供了對J2ME記錄庫的基本的訪問功能.然而,lsMain顯示的開銷項目按照輸入順序排列產生了一個小問題,即查詢某一個項目比較麻煩.

  在本文中,我將介紹RMS的記錄排序API——特別是RecordEnumeration類和 RecordComparator介面,你可以在javax.microedition.rms軟體包中找到這兩者.我同時還要順便談談RecordFilter介面,它可以讓你在記錄庫中查找某個特殊的記錄.你可以在這兒下載最新版本ExpensesApp的代碼.

  用RecordComparator排序在代碼清單 A中,你會發現ExpenseInfo.LoadExpenses又一次被修改了,這次利用RecordEnumeration對象來按照記錄所保存的某項數據,而不是記錄插入的順序,來從記錄庫中查找記錄:RecordEnumeration enu = rs.enumarateRecords(null, new ExpenseComparator, false);

  RecordStore.enumerateRecords接受一個ExpenseComparator類的對象(為參數),ExpenseComparator類實現了RecordComparator的介面,RecordEnumeration用它來確定用來排序的記錄的順序.我在清單B中給出了ExpenseComparator的代碼.

  讓我們來檢測一下RecordComparator.compare方法.Compare方法用於處理兩個記錄,這兩個記錄均處於位元組數組的形式(參數為bytes和bytes1數組),並且必須可以從中提取出任何可以決定先後次序的數據(決定先後次序的方式由RecordEnumeration確定).該方法然後這樣指出這兩個記錄的相對關係::

  如果由bytes代表的記錄(插入時間)在前,那麼compare會返回ExpenseComparator.PRECEDES,並且bytes在bytes1之前出現在枚舉(enumeration)中.

  如果bytes所代表的記錄(的插入時間)在 bytes1所代表的記錄之後,那麼compare返回ExpenseComparator.FOLLOWS,這樣,byteIs在bytes之前出現在枚舉中.

  如果這兩個記錄是等價的(equivalent)(即同一天輸入的),compare返回ExpenseComparator.EQUIVALENT,這兩個記錄的順序任意.

  在ExpenseComparator中,我從這兩個記錄中獲取ExpenseDate欄位(它以「當前時刻的毫秒數」的格式被存到記錄庫中)並根據這兩個記錄的排序返回相應的值.

  實現RecordComparator時,要記住對記錄庫中的每一個記錄至少要調用一次compare方法,(當枚舉開始產生時).,你需要正確引導比較過程,是的這所費時間盡量的短,以免沒有必要地降低應用程序的運行速度.還有一點就是,你用於比較的兩個記錄在無需緊聯(immediately adjacent),分類枚舉.

  使用記錄枚舉

  你也許還記得我在上一篇文章中抱怨使用RecordStore類是如何讓人感到沮喪、而它「名不副實」(相對於RMS API中的其它類)的方法又有多少.再次強調,獲得MIDP類API的JavaDoc文檔將會對你的J2ME工作特別有用.

  再次看看清單A中的代碼,你會注意到現在記錄提取循環(*譯者註:用於提取、讀取記錄的循環*)是用RecordEnumeration.hasNextElement方法做為控制變數的.在以前,每一個開銷項目的ID號保存在ExpenseInfo的一個實例中,記錄中的數據——開銷日期、說明、美元數、美分數(*譯者註:在前面已經說過,J2ME的變數沒有浮點型,花費用美元和美分這兩個整數來表示.*)、歸類——是通過兩個流讀取類來按順序提取的.

  聯合使用RecordEnumeration和xpenseComparator是的lsMain中的開銷項目按項目中的數據的順序來顯示,這就比按照開銷項目插入的順序顯得更加符合邏輯.然而,即使你並沒有打算對記錄進行排序,你也應該考慮用RecordEnumeration來在記錄庫中查詢記錄.這樣做比使用RecordStore類更加簡單,還迴避了使用RecordStore類的幾個潛在問題,如我在上一篇文章結尾所提到的刪除bug.

  棘手的記錄指針

  當你留心這些不一致的方法名稱時,它們就僅僅是一件令人討厭的事而已;但是除此之外,還存在一個更大的、會令你寢食難安的問題.當你偶爾粗略瀏覽文檔后,你可能會想到,僅有nextRecord方法和previousRecord方法可以在枚舉下移動記錄指針.進一步思考後,你會發現並情況不是這樣的,另一個方法也可以操作記錄指針,這就是nextRecordId.

  你必須清楚這個事實,當你希望更新一個記錄之前,獲知它的ID號幾乎是不可避免的.這樣,下面的查詢記錄的方法或許會派上用場:

  調用 nextRecordId來獲取枚舉中下一條記錄的ID號.

  用nextRecord方法得到下一條記錄.

  獲取該記錄中的數據.

  重複上述過程,直到一條記錄.

  上述方法的問題是:由於調用nextRecordId也會移動記錄指針,當你剛剛查詢完一半記錄是,你就捕獲到一個莫名其妙的InvalidRecordIdException例外而不得不重新開始(to boot).

  正如你在代碼清單A中所見,解決第一個問題的方法是用RecordStore.getRecord來取代RecordEnumeration.nextRecord檢索記錄.我知道,這個方法並不完善;但是至少可以工作.那個讓人摸不著頭腦的例外是在記錄指針指到枚舉的一個記錄的情況下調用nextRecordId而產生,你在寫代碼時要注意避免這種情況.

  用RecordFilter來查找記錄

  儘管我沒有在ExpensesApp應用程序中完成它,RecordEnumeration也可能完成搜尋記錄的功能.為了做到這一點,你要向RecordStore.enumerateRecords傳遞一個類(該類實現了RecordFilter的介面)的實例,並完全忽略RecordComparator.RecordFilter僅有一個名為matches方法,它接受一個位元組數組參數(位元組數組代表了某個記錄).該方法用於檢測記錄,並根據被檢測的記錄是否符合預定標準而返回「真」或者「假」.

  舉例來說,假設我們有一個RecordFilter的實現:ExpenseFilter,它在整個記錄庫中搜尋開銷記錄中的「開銷分類(category)」欄位符合ExpenseInfo.CATEGORYMEALS的開銷項目,如代碼清單C所示.為了獲得只有符合上述條件的記錄集合(enumeration,枚舉),我可以這樣組織代碼:RecordStore rs = RecordStore.openRecordStore(RS_NAME);RecordEnumeration enu = es.enumerateRecords(new ExpenseFilter, null, false);

  在這裡,變數enu僅包含分類為「膳食」(這在用戶界面指點)的開銷記錄.

  工作尚未完成,我們仍需努力

  到目前為止,ExpensesApp已經相當完善了.現在,它已經有了個像樣的用戶界面(包括添加新的開銷記錄的快捷方式),也有了些實際用處——在運行過程中存儲信息.但是仍有一些問題:

  新添加的開銷記錄並沒有按照排序插入鏈表中的對應位置.

  ExpenseInfo的實例中的任何改變僅僅更新內存,而沒有考慮到如果該實例已經存檔,還需要將更新后的內容重新存檔——我擔心這一點可能還沒有人看出來.

  本應用程序還不適合在移動設備運行,當它暫停運行時,它沒有試圖釋放它所佔用的資源——而這一點是移動設備應用程序所必須考慮的.

  在下一篇文章中,我將向你介紹如何用「活的」 RecordEnumeration和記錄改變通知API來解決上述缺陷.


[火星人 ] 探索J2ME應用:如何對記錄進行排序已經有670次圍觀

http://coctec.com/docs/java/show-post-59891.html