一.通話記錄的加載過程和大部分的應用類似奠旺,也是異步查詢數(shù)據(jù)庫,得到查詢結(jié)果后再刷新ListView析苫。但是在加載通話記錄時還有一些特別的處理萌狂。特別是在綁定Listview時涉及到了一些復雜的操作。
顯示通話記錄由CallLogFragment.java文件進行處理躏率。在加載通話記錄的過程中還用到了CallLogQueryHandler查詢通話記錄數(shù)據(jù)庫躯畴,CallLogAdapter填充ListView。
查詢通話記錄的過程大致如下:
其中CallLogQueryHandler繼承自CursorQueryHandler薇芝,該類是執(zhí)行異步數(shù)據(jù)庫查詢的常用類蓬抄。以上過程非常的常見,大部分程序都和該流程類似夯到。
1嚷缭、在CallLogFragment的onCreateView中設(shè)置RecyclerView的adapter,并調(diào)用fetchCalls查詢數(shù)據(jù)耍贾。
2阅爽、當查詢完成后會回調(diào)到CallLogFragment的onCallsFetched,并調(diào)用changeCursor荐开,registerContentObserver和registerDataSetObserver付翁,數(shù)據(jù)發(fā)生改變的時候,調(diào)用RecyclerView.Adapter的notifyDataSetChanged就會根據(jù)新的cursor rebind and relayout所有可見的view晃听。
二.關(guān)鍵是在CallLogAdapter?的bindView函數(shù)中執(zhí)行了很多難以理解的操作百侧。通過查看通話記錄的顯示內(nèi)容知道,在通話記錄中顯示了撥打電話的號碼能扒,通話記錄的類型佣渴,該號碼所對應的聯(lián)系人(如果號碼已加入聯(lián)系人)等。當掛斷電話時會查詢聯(lián)系人數(shù)據(jù)庫查找所撥打的電話對應的聯(lián)系人姓名赫粥,并把這些信息寫入通話記錄數(shù)據(jù)庫中观话。因此在通話記錄的數(shù)據(jù)庫中有一列用于存儲聯(lián)系人姓名。但是通話記錄中的聯(lián)系人名稱和聯(lián)系人數(shù)據(jù)庫中的名稱有時候是不一致的越平,通話記錄中的聯(lián)系人名稱只是一個緩存频蛔×槠龋考慮這樣一種情況:當和張三打完電話后,立刻把聯(lián)系人中的張三改為張三三晦溪,然后查看通話記錄會發(fā)現(xiàn)通話記錄也會變成張三三瀑粥,而通話記錄數(shù)據(jù)庫中仍然是張三。
為了使通話記錄中的顯示名稱和聯(lián)系人中的一致三圆,在顯示通話記錄時狞换,需要查詢每個電話號碼對應的聯(lián)系人信息。為了提高效率舟肉,在CallLogAdapter?中用CallLogAdapterExpirableCache數(shù)據(jù)結(jié)構(gòu)緩存查詢到的聯(lián)系人信息修噪,這樣當界面刷新時不需要再次執(zhí)行查詢操作。由于數(shù)據(jù)庫查詢操作比較耗時路媚,在bindView中不可能等到查詢結(jié)果返回之后再顯示界面黄琼。所以在bindView時采用了這樣的處理策略:首先顯示通話記錄中緩存的聯(lián)系人信息,然后開啟一個線程查詢聯(lián)系人信息整慎,并把這些信息緩存起來脏款。該線程的優(yōu)先級比較低,它會等cup空閑時執(zhí)行查詢聯(lián)系人的操作裤园。
如果聯(lián)系人中的信息和通話記錄數(shù)據(jù)庫中的信息不一致(其實這種情況比較少見)撤师,則發(fā)送消息給CallLogAdapter重新執(zhí)行顯示操作。具體的流程如下:
該時序圖只是展現(xiàn)了主要的框架拧揽,忽略了很多細節(jié)剃盾。
其中QueryThead負責查詢聯(lián)系人信息,得到聯(lián)系人信息緩存到ExpirableCache中强法,用于Bindview刷新通話記錄万俗。