會話編輯界面(三)歷史記錄
1、前言
前文對接收者ui有一個簡單的瞭解,下面來看看短信歷史記錄的加載以及界面更新。例如當我們發送一條短信,界面上顯示“正在發送”,發送完後變成“已發送”,以及接收的短信時顯示接收時間等等功能,只所以用單獨的篇幅來講解,主要考慮到該ui的重要性。
2、功能分析
2.1 初始化
短信歷史記錄界面的初始仍然是在ComposeMessageActivity的onCreate方法中通過調用initMessageList方法:
private void initMessageList() {
if (mMsgListAdapter != null) {
return;
}
String highlightString = getIntent().getStringExtra("highlight");
Pattern highlight = highlightString == null
? null
: Pattern.compile("\\b" + Pattern.quote(highlightString), Pattern.CASE_INSENSITIVE);
// Initialize the list adapter with a null cursor.
mMsgListAdapter = new MessageListAdapter(this, null, mMsgListView, true, highlight);
mMsgListAdapter.setOnDataSetChangedListener(mDataSetChangedListener);
mMsgListAdapter.setMsgListItemHandler(mMessageListItemHandler);
mMsgListView.setAdapter(mMsgListAdapter);
mMsgListView.setItemsCanFocus(false);
mMsgListView.setVisibility(View.VISIBLE);
mMsgListView.setOnCreateContextMenuListener(mMsgListMenuCreateListener);
mMsgListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
if (view != null) {
((MessageListItem) view).onMessageListItemClick();
}
}
});
}
該方法初始化用於顯示歷史記錄列表地的Listview,以及用於填充listView的adapter,並設置監聽器和長按menu。2.2 UI分析
2.2.1 UI 簡介
下面就來看看這個歷史記錄是什麼樣的,有哪些界面元素組成,來初步認識一下這個界面。下圖爲短信歷史記錄的ui,
歷史記錄
從上圖可以看出歷史記錄的ui至少包含以下ui組件:聯繫人頭像、聯繫人號碼或者姓名、內容、接收和發送時間,如果是彩信有對應附件、主題的顯示。當然除了這些還有一些錯誤顯示ui等等。
2.2.2 ui佈局分析
要窺探該界面怎麼佈局,首先來看看MessageListAdapter類是如何綁定ui的?該類有兩個重要的方法來完成ui和數據的綁定bindView、newView;
其中newView用於加載佈局文件,定義一個短信ui,bindview用於將從短信數據庫獲取的數據設置到newView上的ui上。這裏來看看系統怎麼定義這個ui的
@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
return mInflater.inflate(R.layout.message_list_item, parent, false);
}
那該ui定義在佈局文件裏面,這裏簡短閒扯android ui的高明,之前有做過J2ME開發的同學可能對android的xml佈局印象深刻,估計有很多同學疑問了J2ME爲啥不引進這個xml佈局,J2ME的ui實現完全靠一行一行的代碼,且複雜冗長,一言難盡哈。這裏來看看神祕的佈局文件。<com.android.mms.ui.MessageListItem
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/msg_list_item"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/listitem_background"
android:orientation="horizontal">
<LinearLayout android:id="@+id/mms_layout_view_parent"
android:paddingLeft="5dip"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical" >
<ViewStub android:id="@+id/mms_layout_view_stub"
android:layout="@layout/mms_layout_view" mms 附件ui,其還有自己的佈局文件,大家都可以查看彩信附件的ui,該ui包含一個iamgeview
android:layout_width="match_parent" 另外就是一個playbutton
android:layout_height="wrap_content"/>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.widget.QuickContactBadge
android:layout_marginLeft="0dip"
android:layout_marginRight="5dip"
android:layout_marginTop="5dip"
android:layout_marginBottom="5dip"
android:id="@+id/avatar"
style="?android:attr/quickContactBadgeStyleWindowSmall" /> 用於顯示聯繫人圖標
<View
android:layout_width="match_parent"
android:layout_height="0dip"
android:layout_below="@id/avatar" />
<LinearLayout android:id="@+id/status_icons"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBottom="@id/text_view" 短信內容包含、主題、時間
android:layout_alignParentRight="true"
android:layout_marginBottom="8dip"
android:orientation="horizontal" >
<ImageView
android:id="@+id/locked_indicator"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_lock_message_sms" 鎖定短信的image,鎖的圖標,該功能就是當你鎖定一條短信後,刪除該會話,該會話的
android:paddingRight="3dip" 其他短信都刪除,但是加鎖的短信不被刪除,這樣可以防止誤刪
android:visibility="gone" />
<ImageView
android:id="@+id/delivered_indicator"
android:layout_width="wrap_content"
android:layout_height="wrap_content" 短信傳送報告,有可能是fail的圖標、以及打開傳送報告後有一個傳送圖標
android:paddingRight="3dip"
android:visibility="gone" />
<ImageView
android:id="@+id/details_indicator"
android:layout_width="wrap_content" 暫時不清楚
android:layout_height="wrap_content"
android:src="@drawable/ic_sms_mms_details"
android:visibility="gone" />
</LinearLayout>
</RelativeLayout>
</LinearLayout>
<ViewStub android:id="@+id/mms_downloading_view_stub"
android:layout="@layout/mms_downloading_view" 如果彩信未下載會顯示該ui,該ui有一個下載button,一個textview,當點擊button
android:layout_gravity="center_vertical" 狀態更新爲正在下載
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</com.android.mms.ui.MessageListItem>
基本上一條短彩信包含的ui就是上述,會根據當前短彩信的狀態來設置來設置對應UI 的值,顯示給用戶,至於如何設置,下回分解。2.2.3 數據的綁定
綁定數據bindView方法來實現,核心的代碼如下
@Override
public void bindView(View view, Context context, Cursor cursor) {
if (view instanceof MessageListItem) {
String type = cursor.getString(mColumnsMap.mColumnMsgType);
long msgId = cursor.getLong(mColumnsMap.mColumnMsgId);
MessageItem msgItem = getCachedMessageItem(type, msgId, cursor);
if (msgItem != null) {
MessageListItem mli = (MessageListItem) view;
MessageItem oldMessageItem = mli.getMessageItem();
if (oldMessageItem != null) {
String oldAddress = oldMessageItem.mAddress;
if (oldAddress != null) {
HashSet<MessageListItem> set = mAddressToMessageListItems.get(oldAddress);
if (set != null) {
set.remove(mli);
}
}
}
mli.bind(mAvatarCache, msgItem); 重要
上面的代碼做的事情很簡單,將查詢到的短信綁定到ui,這裏的綁定涉藉助於MessageListItem的bind方法。對於每個字段怎麼設置的這裏不做解析,有興趣的大家可以看看代碼,很簡單。
2.4 長按按鈕
對於每條短信,這裏給他們設置了一個長按事件,給用戶提供了以下功能。
這裏沒有完全顯示,但我們可以通過代碼知道其具體有哪些功能。mMsgListMenuCreateListener該變量用於創建menu,menu的監聽的監聽事件處理MsgListMenuClickListener來完成。以下代碼是對每個menu的處理
private final class MsgListMenuClickListener implements MenuItem.OnMenuItemClickListener {
public boolean onMenuItemClick(MenuItem item) {
if (!isCursorValid()) {
return false;
}
Cursor cursor = mMsgListAdapter.getCursor();
String type = cursor.getString(COLUMN_MSG_TYPE);
long msgId = cursor.getLong(COLUMN_ID);
MessageItem msgItem = getMessageItem(type, msgId, true);
if (msgItem == null) {
return false;
}
switch (item.getItemId()) {
case MENU_EDIT_MESSAGE: 編輯短信
editMessageItem(msgItem);
drawBottomPanel();
return true;
case MENU_COPY_MESSAGE_TEXT: 複製短信文本
copyToClipboard(msgItem.mBody);
return true;
case MENU_FORWARD_MESSAGE: 轉發短信
forwardMessage(msgItem);
return true;
case MENU_VIEW_SLIDESHOW: 查看幻燈片
MessageUtils.viewMmsMessageAttachment(ComposeMessageActivity.this,
ContentUris.withAppendedId(Mms.CONTENT_URI, msgId), null);
return true;
case MENU_VIEW_MESSAGE_DETAILS: { 查看短信信息:包含短信大小、發送和接收的時間
String messageDetails = MessageUtils.getMessageDetails(
ComposeMessageActivity.this, cursor, msgItem.mMessageSize);
new AlertDialog.Builder(ComposeMessageActivity.this)
.setTitle(R.string.message_details_title)
.setMessage(messageDetails)
.setPositiveButton(android.R.string.ok, null)
.setCancelable(true)
.show();
return true;
}
case MENU_DELETE_MESSAGE: {刪除短信
DeleteMessageListener l = new DeleteMessageListener(
msgItem.mMessageUri, msgItem.mLocked);
confirmDeleteDialog(l, msgItem.mLocked);
return true;
}
case MENU_DELIVERY_REPORT: 短信傳送報告
showDeliveryReport(msgId, type);
return true;
case MENU_COPY_TO_SDCARD: { 複製短信到sdcard
String successMessage = getResources().getString(R.string.copy_to_sdcard_success, SAVED_ATTACHMENT_DIR);
String resultMessage = copyMedia(msgId) ? successMessage : getResources()
.getString(R.string.copy_to_sdcard_fail);
Toast.makeText(ComposeMessageActivity.this, resultMessage, Toast.LENGTH_SHORT).show();
return true;
}
case MENU_COPY_TO_DRM_PROVIDER: {
int resId = getDrmMimeSavedStringRsrc(msgId, copyToDrmProvider(msgId));
Toast.makeText(ComposeMessageActivity.this, resId, Toast.LENGTH_SHORT).show();
return true;
}
case MENU_LOCK_MESSAGE: { 鎖短信
lockMessage(msgItem, true);
return true;
}
case MENU_UNLOCK_MESSAGE: {解鎖
lockMessage(msgItem, false);
return true;
}
case MENU_COPY_TO_SIM: { 複製短信到sim卡
if (hasIccCardCount() > 1) {
String[] items = new String[TelephonyManager.getPhoneCount()];
for (int i = 0; i < items.length; i++) {
items[i] = getMultiSimName(i);
}
CopyToSimSelectListener listener = new CopyToSimSelectListener(msgItem);
new AlertDialog.Builder(ComposeMessageActivity.this)
.setTitle(R.string.copy_to_sim)
.setIcon(android.R.drawable.ic_dialog_info)
.setPositiveButton(android.R.string.ok, listener)
.setSingleChoiceItems(items, 0, listener)
.setCancelable(true)
.show();
} else {
copyToSimWithToast(msgItem);
}
return true;
}
default:
return false;
}
}
}
3、總結
這裏對該ui做了一個簡單的介紹,至於其中一些具體的小細節,可以看一下代碼就明白了。