Conversation(2)ConversationListActivity Date
1:ConversationListrFragment中的数据加载部分
CursorLoader + CursorAdapter
使用CursorLoader的好处是:它可以在后台执行异步的查询操作而且不影响前台UI的交互。并且可以在Activity或者是Fragment中去管理CursorLoader。CursorLoader的使用可以遵循如下的步骤:
1:初始化LoaderManager
2:实现LoaderManager.LoaderCallbacks<Cursor>
3:重写public Loader<Cursor> onCreateLoader(int id, Bundle args) 和public void onLoadFinished(Loader<Cursor> loader, Cursor data) 方法
当Fragmework初始化完成之后,它回去调用onCreateLoader通常查询的动作是在此操作中进行的。可以去实例化一个CursorLoader对象传递查询的URI,字段等信息来完成这一操作。当查询完成之后,会去调用onLoadFinished,在该方法的参数中会有一个Cursor对象,即是你查询之后返回的Cursor,Cursor中包含了查询的结果。
在短信信息加载中,Model是典型的观察者模式的实现方式。对应的类的层次结构为:
LoaderModel extends BaseModel , 在basemodel中,所有的会去维护一个IModeChangeListener的hashset的集合,和静态接口IModeChangeListener,并且要把所有实现了IModeChangeListener的instance的实例,加入到该结合中。在onmodechange方法中,可以遍历hashset,调用IModeChangeListener中的onmodechange方法,这样所有的注册了IModeChangeListener的instance都能收到onmodechange的通知。
在LoaderModel主要是根据Fragment或者是Activity的不同类型去加载Loaderanager。
之后所有的数据加载类都会去继承LoaderModel以便初始化Loaderanager。值得一提的是所有的为了使用Fragmework框架提供的Cursor的方式来加载数据,所有的子model都需要是实现LoaderManager.LoaderCallbacks<Cursor>。实现onCreateLoader,onLoadFinished,onLoaderReset。
当onLoadFinished被调用的时候会得到一个Cursor对象,这个Cursor中维护的就是查询完成之后的数据。当onLoadFinished完成之后,调用momodechange方法,去通知Fragment数据发生了变化,此时可以进一步的去设置Adagper更新UI的数据信息。
具体实现模型和代码如下:
BaseModel
public class BaseModel { public static interface IModelChangeListener { void onModeChange(String event, Object... obj); } private HashSet<IModelChangeListener> mListeners = null; public void addListener(IModelChangeListener listener) { if (listener == null) { return; } if (null == mListeners) { mListeners = new HashSet<BaseModel.IModelChangeListener>(); } mListeners.add(listener); } public void removeListener(IModelChangeListener listener) { if (mListeners == null) { return; } mListeners.remove(listener); } protected void onModelChange(String event, Object... obj) { for (IModelChangeListener listener : mListeners) { listener.onModeChange(event, obj); } } }
LoaderModel
public class LoaderModel extends BaseModel {
protected LoaderManager mLoaderManager = null;
protected void createCursorLoaderForListener(IModelChangeListener listener, int loaderId,
Bundle args, LoaderManager.LoaderCallbacks<Cursor> callback) {
initLoaderManagerFromListener(listener);
if (mLoaderManager != null) {
mLoaderManager.initLoader(loaderId, args, callback);
}
}
protected void initLoaderManagerFromListener(IModelChangeListener listener) {
if(listener == null) {
return;
}
if(listener instanceof Fragment) {
mLoaderManager = ((Fragment)listener).getLoaderManager();
} else if (listener instanceof Activity) {
mLoaderManager = ((Activity)listener).getLoaderManager();
}
}
CursorLoader所接收的参数:
| uri | 应用程度的URI信息:content://sms-mms/conversations sony自己对telephonyProvider对数据库中的字段做了扩充 |
|---|---|
| projection | 查询的参数 |
| selection | A filter declaring which rows to return, formatted as an SQL WHERE clause (excluding the WHERE itself). Passing null will return all rows for the given URI. |
| selectionArgs | You may include ?s in selection, which will be replaced by the values from selectionArgs, in the order that they appear in the selection. The values will be bound as Strings. |
| sortOrder | How to order the rows, formatted as an SQL ORDER BY clause (excluding the ORDER BY itself). Passing null will use the default sort order, which may be unordered. |
所查询的数据库对应的那张表是:mmssms.db semc_thread表
查询的主要的参数信息:
queryProjection.add(SemcThreads._ID); //当前短信的ThreadID,全局唯一
queryProjection.add(SemcThreads.RECIPIENT_IDS);//联系人的ID,指向表 canonical_addresses 里的id
queryProjection.add(SemcThreads.SNIPPET);//如果是文字短信就显示短信内容
queryProjection.add(SemcThreads.SNIPPET_CHARSET);//短信字符编码
queryProjection.add(SemcThreads.SNIPPET_TYPE);//信息类型
queryProjection.add(SemcThreads.UNREAD_COUNT);
queryProjection.add(SemcThreads.SEND_FAILED_COUNT);
queryProjection.add(SemcThreads.DELIVERY_FAILED_COUNT);
queryProjection.add(SemcThreads.DOWNLOAD_FAILED_COUNT);
queryProjection.add(SemcThreads.ADDRESS);
queryProjection.add(SemcThreads.DATE);//短信大小,单位是字节
这个过程所对应的伪代码:
@Override public Loader<Cursor> onCreateLoader(int id, Bundle args) { return new CursorLoader(mContext, SemcThreads.CONTENT_URI, getQueryProjection(), null, null, "date DESC"); } @Override public void onLoadFinished(Loader<Cursor> arg0, Cursor data) { onModelChange(MODEL_EVENT_DATA_LOADED, data); } @Override public void onLoaderReset(Loader<Cursor> arg0) { } private String[] getQueryProjection() { ArrayList<String> queryProjection = new ArrayList<String>(); queryProjection.add(SemcThreads._ID); queryProjection.add(SemcThreads.RECIPIENT_IDS); queryProjection.add(SemcThreads.SNIPPET); queryProjection.add(SemcThreads.SNIPPET_CHARSET); queryProjection.add(SemcThreads.SNIPPET_TYPE); queryProjection.add(SemcThreads.UNREAD_COUNT); queryProjection.add(SemcThreads.SEND_FAILED_COUNT); queryProjection.add(SemcThreads.DELIVERY_FAILED_COUNT); queryProjection.add(SemcThreads.DOWNLOAD_FAILED_COUNT); queryProjection.add(SemcThreads.ADDRESS); queryProjection.add(SemcThreads.DATE); queryProjection.add(SemcThreads.STAR_STATUS); queryProjection.add(SemcThreads.TOTAL_COUNT); return queryProjection.toArray(new String[0]); }
当数据加载完成之后,ConversationListFragment就会接受到通知。
@Override public void onModeChange(String event, Object... obj) { if(TextUtils.equals(event, ConversationListModel.MODEL_EVENT_DATA_LOADED)) { onDataLoaded((Cursor)obj[0]); } }
以上开始数据全部查询完毕。结果:threadId:57 unreadCount:0 sendFailedCount:0 deliveryFailedCount:0 snippet:已经家和平时刻着了吧和吧亲吻了啊很累计时尚可能做事后再 snippetCharset:0 address:8521341024327 recipientIds:54 date1387421990000。
接下来开始UI控件的绑定,来看张流程图片:

1:日期的绑定
2:联系人的绑定(recipientIds)onmodechagne中返回的cursor对象中维护一个recipientIds的字段,该字段是联系人的ID,所谓的ID指的是通过该ID可以在表canional_address中可以通过该ID来查询到Address。
联系人条目显示分为三种情况:a:只有一个联系人 b:有多个联系人 c:没有联系人(草稿箱)
3:头像的显示
SoftReferenct方式缓存用户头像:
public synchronized Bitmap getPersonPhoto(Context context, Uri contactUri) { Bitmap photo = null; SoftReference<Bitmap> ref = mPersonPhotoMap.get(contactUri); if (ref != null) { photo = ref.get(); if (photo == null) { mPersonPhotoMap.remove(contactUri); } } if (photo == null) { if (DEBUG) Log.d(TAG, "Cache miss for photo for contact name (URI = " + contactUri.toString() + ")"); photo = getPhoto(context, contactUri); mPersonPhotoMap.put(contactUri, new SoftReference<Bitmap>(photo)); } return photo; }

浙公网安备 33010602011771号