会话编辑界面(三)历史记录
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做了一个简单的介绍,至于其中一些具体的小细节,可以看一下代码就明白了。