zoukankan      html  css  js  c++  java
  • 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界面到数据加载的主要过程便是这样。

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

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

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

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


  • 相关阅读:
    Maven报错,没有有效的生命周期
    6张图解释IO流
    传统Java JDBC
    快速杀死占用8080端口进程的批处理(kill-8080.bat)
    ubuntu环境配置终极解答
    Linux系统下Java开发环境的配置(未完...)
    Linux常用命令及操作(第二弹)
    Linux下安装Mysql
    Linux常用命令及操作
    int转LPCTSTR
  • 原文地址:https://www.cnblogs.com/bastard/p/2429109.html
Copyright © 2011-2022 走看看