Android ContactsProvider源码分析
2013-04-13 11:26
281 查看
Android源码目录packages\providers下的应用是下载,通话等内置基本应用提供数据存储和操作的provider应用,本文章将针对ContactsProvider源码的架构和实现展开分析。(注:本文使用使用android4.0版本进行分析)
1、架构设计
ContactsProvider中数据操作基类是AbstractContactsProvider.java(参见frameworks\ex\common\java\com\android\common\content\SQLiteContentProvider.java),它继承ContentProvider.java实现SQLiteTransactionListener.java,类结构如下图所示:
图 1 provider结构图
该类是抽象基类,在里面实现了父类的insert、delete和update三个抽象方法,在这三个方法中在其中使用了事务对数据库进行操作。该类设计时,使用了模板模式模板方法为insertInTransaction,updateInTransaction和deleteInTransaction。该类在对数据库进行事务操作的同时,对子类开放了onRollback,onCommit等事物回调方法,子类可以根据自己的业务特点进行扩展。增删改查的调用过程如下图2
3 4所示:
图2 插入操作
图 3 更新操作
图 4 删除操作
在整个设计中有两个类继承了AbstractContactsProvider.java,一个是ContactsProvider2.java,我们在调用系统的联系人数据时基本都是调用该类,里面封装了所有联系人的数据操作。第二个是ProfileProvider.java,该类是ContactsProvider2.java的委托类。这三个类的类间关系如下图5所示:
图 5 类间关系图
类ContactsTransaction.java是对事务的管理类,主要对进行的事务进行管理,类似一个事务池。是AbstractContactsProvider.java中事务处理的核心类。
DataRowHandler.java是数据处理抽象类,实现了对数据的增删改操作,子类有如下几个:
这些子类在ContactsProvider2#initDataRowHandlers中初始化
这些子类在getDataRowHandler方法中中通过mimetype进行调用:
getDataRowHandler方法在insertData,deleteData和updateData方法中被调用。
所有数据的mimetype都被存储在表Tables.MIMETYPES中,该只有两个字段_id和mimetype。
Tables.MIMETYPES表数据的存储是在ContactsDatabaseHelper#lookupAndCacheId中进行的,具体调用过程如下图 6 所示:
图 6 mimetype数据调用流程图
2、表结构
ContactsProvider 中共创建了25张表,
这些表数据对开发者开放的api在 \frameworks\base\core\java\android\provider\文件夹下,
由于数据查询涉及多个表间关系,大量数据的查询都是通过视图来完成的,创建了如下8个视图,而这几个视图是大家在调用api进行查询时显示的数据:
4、总结
ContactsProvder是provider源码中数据处理和架构比较全面的一个应用,可以将它的架构核心抽离出来供大家参考和借鉴,以下类构成了整个架构的核心类,可以重点研究:
1、架构设计
ContactsProvider中数据操作基类是AbstractContactsProvider.java(参见frameworks\ex\common\java\com\android\common\content\SQLiteContentProvider.java),它继承ContentProvider.java实现SQLiteTransactionListener.java,类结构如下图所示:
图 1 provider结构图
该类是抽象基类,在里面实现了父类的insert、delete和update三个抽象方法,在这三个方法中在其中使用了事务对数据库进行操作。该类设计时,使用了模板模式模板方法为insertInTransaction,updateInTransaction和deleteInTransaction。该类在对数据库进行事务操作的同时,对子类开放了onRollback,onCommit等事物回调方法,子类可以根据自己的业务特点进行扩展。增删改查的调用过程如下图2
3 4所示:
图2 插入操作
图 3 更新操作
图 4 删除操作
在整个设计中有两个类继承了AbstractContactsProvider.java,一个是ContactsProvider2.java,我们在调用系统的联系人数据时基本都是调用该类,里面封装了所有联系人的数据操作。第二个是ProfileProvider.java,该类是ContactsProvider2.java的委托类。这三个类的类间关系如下图5所示:
图 5 类间关系图
类ContactsTransaction.java是对事务的管理类,主要对进行的事务进行管理,类似一个事务池。是AbstractContactsProvider.java中事务处理的核心类。
DataRowHandler.java是数据处理抽象类,实现了对数据的增删改操作,子类有如下几个:
DataRowHandlerForCommonDataKind.java DataRowHandlerForCustomMimetype.java DataRowHandlerForEmail.java DataRowHandlerForGroupMembership.java DataRowHandlerForIm.java DataRowHandlerForNickname.java DataRowHandlerForNote.java DataRowHandlerForOrganization.java DataRowHandlerForPhoneNumber.java DataRowHandlerForPhoto.java DataRowHandlerForStructuredName.java DataRowHandlerForStructuredPostal.java
这些子类在ContactsProvider2#initDataRowHandlers中初始化
private void initDataRowHandlers(Map<String, DataRowHandler> handlerMap, ContactsDatabaseHelper dbHelper, ContactAggregator contactAggregator, PhotoStore photoStore) { Context context = getContext(); handlerMap.put(Email.CONTENT_ITEM_TYPE, new DataRowHandlerForEmail(context, dbHelper, contactAggregator)); handlerMap.put(Im.CONTENT_ITEM_TYPE, new DataRowHandlerForIm(context, dbHelper, contactAggregator)); handlerMap.put(Organization.CONTENT_ITEM_TYPE, new DataRowHandlerForOrganization(context, dbHelper, contactAggregator)); handlerMap.put(Phone.CONTENT_ITEM_TYPE, new DataRowHandlerForPhoneNumber(context, dbHelper, contactAggregator)); handlerMap.put(Nickname.CONTENT_ITEM_TYPE, new DataRowHandlerForNickname(context, dbHelper, contactAggregator)); handlerMap.put(StructuredName.CONTENT_ITEM_TYPE, new DataRowHandlerForStructuredName(context, dbHelper, contactAggregator, mNameSplitter, mNameLookupBuilder)); handlerMap.put(StructuredPostal.CONTENT_ITEM_TYPE, new DataRowHandlerForStructuredPostal(context, dbHelper, contactAggregator, mPostalSplitter)); handlerMap.put(GroupMembership.CONTENT_ITEM_TYPE, new DataRowHandlerForGroupMembership(context, dbHelper, contactAggregator, mGroupIdCache)); handlerMap.put(Photo.CONTENT_ITEM_TYPE, new DataRowHandlerForPhoto(context, dbHelper, contactAggregator, photoStore)); handlerMap.put(Note.CONTENT_ITEM_TYPE, new DataRowHandlerForNote(context, dbHelper, contactAggregator)); }
这些子类在getDataRowHandler方法中中通过mimetype进行调用:
public DataRowHandler getDataRowHandler(final String mimeType) { if (inProfileMode()) { return getDataRowHandlerForProfile(mimeType); } DataRowHandler handler = mDataRowHandlers.get(mimeType); if (handler == null) { handler = new DataRowHandlerForCustomMimetype( getContext(), mContactsHelper, mContactAggregator, mimeType); mDataRowHandlers.put(mimeType, handler); } return handler; }
getDataRowHandler方法在insertData,deleteData和updateData方法中被调用。
/** * Inserts an item in the data table * * @param values the values for the new row * @return the row ID of the newly created row */ private long insertData(ContentValues values, boolean callerIsSyncAdapter) { long id = 0; mValues.clear(); mValues.putAll(values); long rawContactId = mValues.getAsLong(Data.RAW_CONTACT_ID); // Replace package with internal mapping final String packageName = mValues.getAsString(Data.RES_PACKAGE); if (packageName != null) { mValues.put(DataColumns.PACKAGE_ID, mDbHelper.get().getPackageId(packageName)); } mValues.remove(Data.RES_PACKAGE); // Replace mimetype with internal mapping final String mimeType = mValues.getAsString(Data.MIMETYPE); if (TextUtils.isEmpty(mimeType)) { throw new IllegalArgumentException(Data.MIMETYPE + " is required"); } mValues.put(DataColumns.MIMETYPE_ID, mDbHelper.get().getMimeTypeId(mimeType)); mValues.remove(Data.MIMETYPE); DataRowHandler rowHandler = getDataRowHandler(mimeType); id = rowHandler.insert(mActiveDb.get(), mTransactionContext.get(), rawContactId, mValues); if (!callerIsSyncAdapter) { mTransactionContext.get().markRawContactDirty(rawContactId); } mTransactionContext.get().rawContactUpdated(rawContactId); return id; }
所有数据的mimetype都被存储在表Tables.MIMETYPES中,该只有两个字段_id和mimetype。
db.execSQL("CREATE TABLE " + Tables.MIMETYPES + " (" + MimetypesColumns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," + MimetypesColumns.MIMETYPE + " TEXT NOT NULL" + ");");
Tables.MIMETYPES表数据的存储是在ContactsDatabaseHelper#lookupAndCacheId中进行的,具体调用过程如下图 6 所示:
图 6 mimetype数据调用流程图
2、表结构
ContactsProvider 中共创建了25张表,
public static final String CONTACTS = "contacts"; public static final String RAW_CONTACTS = "raw_contacts"; public static final String STREAM_ITEMS = "stream_items"; public static final String STREAM_ITEM_PHOTOS = "stream_item_photos"; public static final String PHOTO_FILES = "photo_files"; public static final String PACKAGES = "packages"; public static final String MIMETYPES = "mimetypes"; public static final String PHONE_LOOKUP = "phone_lookup"; public static final String NAME_LOOKUP = "name_lookup"; public static final String AGGREGATION_EXCEPTIONS = "agg_exceptions"; public static final String SETTINGS = "settings"; public static final String DATA = "data"; public static final String GROUPS = "groups"; public static final String PRESENCE = "presence"; public static final String AGGREGATED_PRESENCE = "agg_presence"; public static final String NICKNAME_LOOKUP = "nickname_lookup"; public static final String CALLS = "calls"; public static final String STATUS_UPDATES = "status_updates"; public static final String PROPERTIES = "properties"; public static final String ACCOUNTS = "accounts"; public static final String VISIBLE_CONTACTS = "visible_contacts"; public static final String DIRECTORIES = "directories"; public static final String DEFAULT_DIRECTORY = "default_directory"; public static final String SEARCH_INDEX = "search_index"; public static final String VOICEMAIL_STATUS = "voicemail_status";
这些表数据对开发者开放的api在 \frameworks\base\core\java\android\provider\文件夹下,
CallLog.java Contacts.java ContactsContract.java SocialContract.java SyncConstValue.java VoicemailContract.java
由于数据查询涉及多个表间关系,大量数据的查询都是通过视图来完成的,创建了如下8个视图,而这几个视图是大家在调用api进行查询时显示的数据:
public interface Views { public static final String DATA = "view_data"; public static final String RAW_CONTACTS = "view_raw_contacts"; public static final String CONTACTS = "view_contacts"; public static final String ENTITIES = "view_entities"; public static final String RAW_ENTITIES = "view_raw_entities"; public static final String GROUPS = "view_groups"; public static final String DATA_USAGE_STAT = "view_data_usage_stat"; public static final String STREAM_ITEMS = "view_stream_items"; }
4、总结
ContactsProvder是provider源码中数据处理和架构比较全面的一个应用,可以将它的架构核心抽离出来供大家参考和借鉴,以下类构成了整个架构的核心类,可以重点研究:
AbstractContactsProvider.java ContactAggregator.java ContactsDatabaseHelper.java ContactsProvider2.java ContactsTransaction.java TransactionContext.java
相关文章推荐
- Android Contacts 联系人源码分析
- Android 5.1 Contacts源码分析(五):PeopleActivity
- Android 5.0 Contacts源码分析
- Android DownloadProvider 源码分析
- Android Contacts源码分析二——(PeopleActivity)分析
- Android 5.1 Contacts源码分析(四):Contacts模块ListView Adapter结构
- Android Contacts 联系人源码分析
- Android Contacts源码分析
- Android 5.1 Contacts源码分析(一):Contacts模块文件结构
- Android 4.0 Contacts 通话记录界面的分析(源码)
- android源码分析--Mms、Contacts、Dialer
- Android 5.1 Contacts源码分析(三):Contacts模块Fargment结构
- Android 5.0 Contacts源码分析
- Android 5.0 Contacts源码分析
- Android 5.1 Contacts源码分析(二):Contacts模块主要窗口
- Android IPC 通讯机制源码分析【中】
- Android IntentService浅谈以及源码分析
- android launcher源码分析
- Android源码分析之拍照、图片、录音、视频和音频功能
- MPAndroidChart之LineChart源码分析