Anlyze ConversationList In Qcom
The first UI In MMS is ConversationList


Main flow of loading data

1:在ConversationList的onCreate()函数被调用时,会新建一个异步加载handler, new ThreadListQueryHandler,这个handler里面的新建thread进行异步查询的功能。
2:onStart()调用时会调用到startAsyncQuery()函数,这个函数顾名思义就是与数据查询相关。
3:跳转到了conversation的 StartQuery()函数中, 这里有设置uri,projection,selection,uri= sAllThreadsUri= Threads.CONTENT_URI.buildUpon().appendQueryParameter("simple", "true").build() projection =ALL_THREADS_PROJECTION(这里几乎返回了thread table中的所有列),selection = null, dort =Conversations.DEFAULT_SORT_ORDER。这里调用的是传进来的handler.StartQuery()。而这个handler就是我们在onCreate()中创建的ThreadListQueryHandler。
PS: 查看AsyncQueryHandler的时候注意理清thread,handler,looper和messagequeue的关系。
4:我们继续跟踪在AsyncQueryHandler中startQuery的流程,发送查询事件消息。 由mWorkerThreadHandler的handleMessage()来执行resolver.Query()操作。并将查询结果以消息的形式转发给this.
5:由AsyncQueryHandler的handleMessage()来调用onQueryComplete()函数,这个函数在ThreadListQueryHandler被重写。
6:在ConversationList的ThreadListQueryHandler中实现了onQueryComplete()函数,这里我们根据处理结果,mListAdapter.changeCursor(),来更新界面,如果cursor.getCount()=0, 就显示无会话。

handler的继承关系和说明

1:ThreadListQueryHandler是ConversationList中的内部类,在onCreate中初始化,用于异步加载数据
2,根据上图我们可以看出 ThreadListQueryHandler的层级继承关系,而这里最重要的就是AsyncQueryHandler, 这个类新建了一个thread,用新建thread的looper构建一个mWorkerThreadHandler, 在这个handler中的handleMessage里进行resolver.Query()的操作,并且将得到的cursor,传递到了基于主UI线程的AsyncQueryHandler自身的handleMessage中来使用。
PS:特别注意里面两个handleMessage的关系,主UI线程和新建thread的消息传递

解析Uri 和 查询的 参数

1: Threads.CONTENT_URI.buildUpon().appendQueryParameter("simple", "true").build()是Uri的赋值
2:通过在/msm8916/frameworks/opt/telephony/src/java/android/provider/Telephony.java中查询得出content://mms-sms/conversations
3:在MmsSmsProvider中query的case是URI_CONVERSATIONS。同时传递参数为String simple = uri.getQueryParameter("simple"),所以进行getSimpleConversations查询
4:mOpenHelper.getReadableDatabase().query(TABLE_THREADS, projection,selection, selectionArgs, null, null, " date DESC"),这里得出是在threads表中查询

[edit]Data加载到ConversationList的过程


1:在ConversationListAdapter中调用bindView

   public void bindView(View view, Context context, Cursor cursor) {
       if (!(view instanceof ConversationListItem)) {
           Log.e(TAG, "Unexpected bound view: " + view);
           return;
       }
       ConversationListItem headerView = (ConversationListItem) view;
       Conversation conv = Conversation.from(context, cursor);
       headerView.bind(context, conv);
   }

2:在conversation中调用from函数得到一个conversation,其中涉及到缓存

   public static Conversation from(Context context, Cursor cursor) {
       // First look in the cache for the Conversation and return that one. That way, all the
       // people that are looking at the cached copy will get updated when fillFromCursor() is
       // called with this cursor.
       long threadId = cursor.getLong(ID);
       if (threadId > 0) {
           Conversation conv = Cache.get(threadId);
           if (conv != null) {
               fillFromCursor(context, conv, cursor, false);   // update the existing conv in-place
               return conv;
           }
       }
       Conversation conv = new Conversation(context, cursor, false);
       try {
           Cache.put(conv);
       } catch (IllegalStateException e) {
           LogTag.error(TAG, "Tried to add duplicate Conversation to Cache (from cursor): " +
                   conv);
           if (!Cache.replace(conv)) {
               LogTag.error("Converations.from cache.replace failed on " + conv);
           }
       }
       return conv;
   对已经在缓存中的数据,直接拿出来用,没有的对cache进行填充

3:其中cache初始化个HashSet 10个空间的样子

       private static Cache sInstance = new Cache();
       static Cache getInstance() { return sInstance; }
       private final HashSet<Conversation> mCache;
       private Cache() {
           mCache = new HashSet<Conversation>(10);
       }

超过10个cache进行 add 操作。
4:得到conversation后到ConversationListItem中的bind函数中 对listview的控件赋值。

更多推荐

高通Android 4.4 短信应用ConversationList 的分析