Mms模块ConversationList流程分析(2)

接上一篇:Mms模块ConversationList流程分析(1)


三 联系人数据的查询

  前面使用AsyncQueryHandler所获取到的cursor仅仅是查询了,所有对话信息数据;但是其中的联系人仅仅只是保存了其ID:recipientIds;

  还需要根据此recipientIds获取其联系人的信息;这个就是在包装信息数据给ListItem使用的时候获取的;

Conversation conv = Conversation.from(context, cursor);获取联系人相关信息;

下面看下这个过程:

        

         先从Conversation中的Cache中查找是否当前cursor所对应的Thread信息已存在于缓存中,

若存在则将其更新并返回;否则新创建,并将其加入到缓存Cache中;

         public static Conversation from(Context context, Cursor cursor) {

        long threadId = cursor.getLong(ID);

        if (threadId > 0) {

                            //Conversation缓存中查找cursor所对应的Thread信息

            Conversation conv = Cache.get(threadId);

            if (conv != null) {

 

                                     //已存在缓存中 update the existing conv in-place

                fillFromCursor(context, conv, cursor, false);                  

return conv;

            }

        }

                   //不存在于缓存中,新创建

        Conversation conv = new Conversation(context, cursor, false);           

Cache.put(conv);

        return conv;

    }

        

         实际上不管是更新还是创建 都会走函数fillFromCursor();

那么下面看看这个函数都干了些什么事情;

private static void fillFromCursor(Context context, Conversation conv,

                              Cursor c, boolean allowQuery) {

synchronized (conv) {

         //填写conv实例基本的对话信息 ThreadIddatecountattachtype等;

}

 

//获取cursor中联系人Ids

String recipientIds = c.getString(RECIPIENT_IDS);

//通过recipientIds 获取对应的联系人数据:addressname……

ContactList recipients = ContactList.getByIds(recipientIds, allowQuery);

 

synchronized (conv) {

         //关联联系人数据

         conv.mRecipients = recipients;

         //计算未读信息条数

}

}

         (注意这里的synchronized的用法,这个是线程相关,这里不详细分析)

——》ContactList.getByIds

这里就转到ContactList类里面操作去了()这里还是mms的data包下里面的类;

 

1 ContactList

       到此查询过程如下:

下面几个部分就围绕这个流程图进行详细介绍;

         ContactList

         此类从ArrayList继承下来:public class ContactList extends ArrayList<Contact>{}

public static ContactList getByIds(String spaceSepIds, boolean canBlock) {

  ContactList list = new ContactList();

  //foreach语句

  for (RecipientIdCache.Entry entry : RecipientIdCache

  .getAddresses(spaceSepIds)) {        //根据Id获取号码 访问数据库

  if (entry != null && !TextUtils.isEmpty(entry.number)) {

         //根据号码获取联系人数据

  Contact contact = Contact.get(entry.number, canBlock);

  contact.setRecipientId(entry.id);

  list.add(contact);

  }

  }

  //返回联系人列表 Conversation

  return list;

}

 

通过这里Contact contact = Contact.get(entry.number, canBlock); 传入号码

——》转到Contact里面执行;

下面看看这个类的get方法

 

2 Contact 异步或者阻塞方式获取联系人数据

       number联系人的号码

         canBlock将决定是以阻塞的方式还是异步的方式获取联系人数据

public static Contact get(String number, boolean canBlock) {

         //调用的是ContactsCache类实例的get方法

    return sContactCache.get(number, canBlock);

}

 

下面看一下ContactsCache里面的get方法

ContactsCacheContact类的内部类;  

public Contact get(String number, boolean canBlock) {

                   //返回一个contact不管数据库中是否存在 先从内部缓存中查找匹配号码的

                   //若不存在则直接将其返回,若不存在则返回新创建一个

  Contact contact = get(number);      //内部查找

        Runnable r = null;

        synchronized (contact) {

  while (canBlock && contact.mQueryPending) {      //是否阻塞方式

  contact.wait();                   }

  final Contact c = contact;         //匿名内部类实现线程

  r = new Runnable() {

  public void run() {    

         //仍然要在线程中更新,填充联系人数据 不管是否从缓存中取得

  updateContact(c);  }       

  };       }

  if (canBlock) {

  r.run();      //阻塞方式

  } else {

  pushTask(r);     //异步方式               }

  return contact;

}

 

通过此方法异步或者阻塞方式获取到的联系人数据 通过此get方法得到的联系人数据可能仅仅只是包含号码,而没有其他数据信息;

 

下面看一下updateContact方法

private void updateContact(final Contact c) {

Contact entry = getContactInfo(c.mNumber);

 

         //从数据库中获取Contact数据

  Contact entry = getContactInfo(c.mNumber);

  //设置Contact实例c的数据信息:name id……

 

  //notify to update who?

  //who? Here It is ConversationListItem

  UpdateListener l;//从Contact的UpdateListener队列中获取一个Listener对象

  //更新当前监听者所使用的Contact数据

  l.onUpdate(c)

}

3 ContactupdateListener的添加

这里存在一个updateListener对象就是 ConversationListItem实例:什么时候传进去的呢?

看到 bind方法被调用时 也就是 上面所讲bindView时;

public final void bind(){

         ……

         Contact.addListener(this); //添加UpdateListener

}

 

4 联系人处理方式

Contact处理联系人数据有两种方式:异步和阻塞;具体这里不作详细分析;

 

那么这里有个点让我不明白!

1)   加载一个Thread ListItem对应的联系人数据 可能有多个 是在一个ContactList  getByIds方法中for循环执行;

2)   异步方式单独处理每一个号码对应的联系人数据

3)   将pushTask(r);加入到TaskStack中之后,放弃对CPU的控制权;

4)   TaskStack中线程mWorkerThread;异步执行存在很多的不确定性,怎么控制;

5)   一次异步方式执行updateContact会去通知ItemList更新数据,为什么不是选择一个Thread信息所有的号码处理完毕 之后再去更新ItemList;

是这么个道理: 加入TaskStack中时;执行:

public void push(Runnable r) {

                synchronized (mThingsToLoad) {

                    mThingsToLoad.add(r);

                    mThingsToLoad.notify();  //放弃资源控制

                }

            } 这里就等待getByIds将所有的号码处理加入到TaskStack中来处理;

                   但是仍然是每一次线程run方法都会去更新;也就是更新一个联系人就要更新UI一次。这样岂不浪费时间和资源;

这个mWorkerThread线程是在启动MmsApp时候就启动了

MmsApp.java中

@Override

public void onCreate(){

                   ……

  //创建ContactsCache对象,ContactsCache创建TaskStack对象

  //TaskStack是ContactsCache内部类 其构造函数启动线程

  Contact.init(this);

}

 

这个Mms这个联系人管理是比较的复杂!这里所认识的可能并一定正确;待后续完善。

 

 

五 数据更新到界面更新

回到ConversationListAdapter的函数bindView函数中来

@Override

    public void bindView(View view, Context context, Cursor cursor) {

        ConversationListItem headerView = (ConversationListItem) view;

        Conversation conv = Conversation.from(context, cursor);

        ConversationListItemData ch = new ConversationListItemData(context, conv);

        headerView.bind(context, ch);

    }

 

       需要看一下headerView.bind所执行的bind函数:

//更新ListViewItem中控件的相关内容

void bind(Context context, final ConversationListItemData ch) {

                   ……

        // Date

        mDateView.setText(ch.getDate());

        // From.

        mFromView.setText(formatMessage(ch));

        // Register for updates in changes of any of the contacts in this conversation.

        ContactList contacts = ch.getContacts();

        Contact.addListener(this);                // onUpdate函数

        // Subject

        mSubjectView.setText(ch.getSubject());

                  //avatar

        updateAvatarView();

}

 

整个ConversationList界面到数据加载的主要过程便是这样。

 

这里仅仅只是一个框架性的对各个模块进行分析和介绍;

具体各个模块还需要进一步的详细分析。

其中可能存在有些地方并不正确,欢迎指正;

或将待后续深入了解之后进行更正更新。


posted @ 2012-04-01 17:23  __Shadow  阅读(2603)  评论(0编辑  收藏  举报