Dialer 联系人加载

2,联系人加载

联系人加载主要是Dialer中的联系人加载,界面如下,


界面对应的Fragment为AllContactsFragment,在ListsFragment的内部类ViewPagerAdapter的getItem方法部分代码如下,

case TAB_INDEX_ALL_CONTACTS:
    mAllContactsFragment = new AllContactsFragment();
    return mAllContactsFragment;

在论述联系人之前,先论述一下LoaderManager原理。LoaderManager原理参考 

LoaderManager源码分析之一

LoaderManager源码分析之二

2.2联系人加载

AllContactsFragment的架构图如下,


1,初始化

ContactEntryListFragment的onCreate方法主要逻辑如下,

1,调用createListAdapter方法创建Adapter 对象,

mAdapter = createListAdapter();

ContactEntryListFragmentcreateListAdapter方法是一个抽象方法,因此需要子类实现,

protected abstract T createListAdapter();

AllContactsFragment的createListAdapter方法如下,

final DefaultContactListAdapter adapter = new DefaultContactListAdapter(getActivity()) {
  @Override
  protected void bindView(View itemView, int partition, Cursor cursor, int position) {
      super.bindView(itemView, partition, cursor, position);
      itemView.setTag(this.getContactUri(partition, cursor));
      }
  };
adapter.setDisplayPhotos(true);
adapter.setFilter(ContactListFilter.createFilterWithType(
                ContactListFilter.FILTER_TYPE_DEFAULT));
adapter.setSectionHeaderDisplayEnabled(isSectionHeaderDisplayEnabled());
return adapter;

构造了一个匿名DefaultContactListAdapter对象,并覆盖了DefaultContactListAdapter的bindView方法。

当然,最后在onCreateView方法中将该Adapter设置为listview的Adapter,

mListView.setAdapter(mAdapter);

2,注册IntentFilter,监听SIM卡状态的变化,监听飞行模式状态,

IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);

ContactEntryListFragment的onStart方法中会调用startLoading方法开始读取联系人,

startLoading();

startLoading 方法最终会调用LoaderManager的initLoader方法开始查询。

设置查询语句,DefaultContactListAdapter的configureLoader方法后面会论述。

2,界面加载

LoaderManager查询完成之后, AllContactsFragment的onLoadFinished方法调用流程图如下,


AllContactsFragment的onLoadFinished方法逻辑如下,

1,首先调用父类的ContactEntryListFragment的onLoadFinished方法进行处理,

super.onLoadFinished(loader, data);

2,如果联系人为空,则显示mEmptyListView。

if (data == null || data.getCount() == 0) {
   mEmptyListView.setVisibility(View.VISIBLE);
}

ContactEntryListFragment的onLoadFinished方法逻辑如下,

onPartitionLoaded(loaderId, data); //处理查询的Cursor
if (isSearchMode()) { //如果是搜索联系人
  •••
} else {
  mDirectoryListStatus = STATUS_NOT_LOADED;
  getLoaderManager().destroyLoader(DIRECTORY_LOADER_ID);
   //调用LoaderManager的destroyLoader方法终止
}

onPartitionLoaded方法如下,

mAdapter.changeCursor(partitionIndex, data);

会调用DefaultContactListAdapter的changeCursor方法.虽然父类ContactListAdapter实现了changeCursor方法,还是直接看CompositeCursorAdapter的changeCursor方法,逻辑如下,

notifyDataSetChanged();

会调用notifyDataSetChanged方法, notifyDataSetChanged原理在此就不论述了,会调用list Adapter的getView方法重新加载信息并绘制界面。

CompositeCursorAdapter的getView方法调用流程图如下,


CompositeCursorAdapter的getView方法逻辑如下,

1,如果是view类型时头,就调用getHeaderView方法获取view,

if (offset == -1) {
     view = getHeaderView(i, mPartitions.get(i).cursor, convertView, parent);
}

getHeaderView方法如下,

View view = convertView != null? convertView
   : newHeaderView(mContext, partition, cursor, parent);
bindHeaderView(view, partition, cursor);
return view;

调用ContactEntryListAdapter的newHeaderView和bindHeaderView方法完成。

2,调用getView方法显示联系人信息,

view = getView(i, mPartitions.get(i).cursor, offset, convertView, parent);

getView 逻辑很简单,如果存在就直接获取,否则调用newView方法获取,最后调用bindView方法,

View view;
if (convertView != null) {
     view = convertView;
} else {
     view = newView(mContext, partition, cursor, position, parent);
}
bindView(view, partition, cursor, position);
return view;

ContactEntryListAdapter是肯定需要实现newView和bindView方法的。

一般ContactEntryListAdapter的子类方法会调用ContactEntryListAdapter的newView和bindView方法。

 newView 主要是构造view对象, ContactListAdapter的newView方法如下,

ContactListItemView view = super.newView(context, partition, cursor, position, parent);
view.setUnknownNameText(mUnknownNameText);
view.setQuickContactEnabled(isQuickContactEnabled());
view.setAdjustSelectionBoundsEnabled(isAdjustSelectionBoundsEnabled());
view.setActivatedStateSupported(isSelectionVisible());
if (mPhotoPosition != null) {
   view.setPhotoPosition(mPhotoPosition);
}
return view;

首先调用父类ContactEntryListAdapter的newView方法构造ContactListItemView对象,如下,

final ContactListItemView view = new ContactListItemView(context, null);
view.setIsSectionHeaderEnabled(isSectionHeaderDisplayEnabled());
view.setAdjustSelectionBoundsEnabled(isAdjustSelectionBoundsEnabled());
return view;

ContactListItemView继承于ViewGroup,因此,本质上还是一个view。

DefaultContactListAdapter的bindView方法主要逻辑如下,

1,调用父类的bindView方法,

super.bindView(itemView, partition, cursor, position);
final ContactListItemView view = (ContactListItemView)itemView; //强制类型转换

2,是否高亮显示(只有在查询状态才会高亮显示)

view.setHighlightedPrefix(isSearchMode() ? getUpperCaseQueryString() : null);

3,首字符显示,

bindSectionHeaderAndDivider(view, position, cursor);

4,显示联系人图标

if (isQuickContactEnabled()) {
   bindQuickContact(view, partition, cursor, ContactQuery.CONTACT_PHOTO_ID,
      ContactQuery.CONTACT_PHOTO_URI, ContactQuery.CONTACT_ID,
      ContactQuery.CONTACT_LOOKUP_KEY, ContactQuery.CONTACT_DISPLAY_NAME,
ContactQuery.CONTACT_ACCOUNT_TYPE, ContactQuery.CONTACT_ACCOUNT_NAME);
} else {
    if (getDisplayPhotos()) {
        bindPhoto(view, partition, cursor);
    }
}

PhoneNumberListAdapter里面的bindView函数调用的是bindQuickContact(QuickContactBadge),DefaultContactListAdapter调用了bindPhoto(ImageView函数,但是其他流程一模一样。在各自对应的Fragement里面调用setQuickContactEnabled来设置。在这里仅描述DefaultContactListAdapter的流程。

5,显示联系人的其他信息,

bindNameAndViewId(view, cursor); // 显示姓名
bindPresenceAndStatusMessage(view, cursor);// 显示联系人后面的拨号图标
if (isSearchMode()) {
   bindSearchSnippet(view, cursor);// 处于查询状态时,显示号码或者其他
} else {
   view.setSnippet(null);//处于没有查询的状态,不显示号码或者其他
}
bindPresenceAndStatusMessage,只有contact才显示联系人后面的图标。
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值