联系人重启或者重置之后快速添加联系人,拨打电话无头像
ContactsProvider在首次initialize的时候会执行scheduleBackgroundTask(BACKGROUND_TASK_CLEANUP_PHOTOS);
将数据库里面没有的联系人的头像资源清除掉,即清除/data/data/com.android.providers.contacts/files/photos下面的头像文件。
判断的标准见:
protected void cleanupPhotoStore() {
final SQLiteDatabase db = mDbHelper.get().getWritableDatabase();
// Assemble the set of photo store file IDs that are in use, and send those to the photo
// store. Any photos that aren't in that set will be deleted, and any photos that no
// longer exist in the photo store will be returned for us to clear out in the DB.
long photoMimeTypeId = mDbHelper.get().getMimeTypeId(Photo.CONTENT_ITEM_TYPE);
Cursor c = db.query(Views.DATA, new String[]{Data._ID, Photo.PHOTO_FILE_ID},
DataColumns.MIMETYPE_ID + "=" + photoMimeTypeId + " AND "
+ Photo.PHOTO_FILE_ID + " IS NOT NULL", null, null, null, null);
Set<Long> usedPhotoFileIds = Sets.newHashSet();
Map<Long, Long> photoFileIdToDataId = Maps.newHashMap();
try {
while (c.moveToNext()) {
long dataId = c.getLong(0);
long photoFileId = c.getLong(1);
usedPhotoFileIds.add(photoFileId);
photoFileIdToDataId.put(photoFileId, dataId);
}
} finally {
c.close();
}
。。。。。。。
。。。。。。。
Set<Long> missingPhotoIds = mPhotoStore.get().cleanup(usedPhotoFileIds);
。。。。。。。
。。。。。。。
}
即:View.Data中有记载的资源不会被清除
清除的资源记载在PhotoStore的map对象中
private final Map<Long, Entry> mEntries;
Key值是头像资源的名字,对应View.Data中的Photo.PHOTO_FILE_ID字段, 详情分析可见前面的头像保存文章。
每次保存一个联系人的头像就会将头像资源的名字当作id,头像资源信息封装成Entry存储到mEntries中,
执行清理还有一个条件,至少要一天的时间间隔。
每次重启或者acore进程重建或者待机超过一天都会执行清理动作,
想想看nEntries在内存中,每次重启或者acore进程重建的时候肯定为空,没有清理意义,
所以该清理动作的意义就是为了防止长时间待机情况下,删除了很多联系人而没有清理头像资源的情况
(Warnning: 删除一个联系人的时候头像资源不会删除)
后面测试测出一个问题:
手机恢复出厂设置后快速去创建联系人,然后拨打电话,通话界面没有头像:
这个原因就是清理的动作和保存的动作没有同步,
在头像原图保存成功后(见PhotoStore中insert函数),但是还没将头像信息更新到Data表中(见ContactsProvider.PipeMonitor中的doInBackground)的时候, 执行了cleanupPhotoStore动作,参照上面函数查询逻辑,肯定没有查询到刚保存的头像原图信息,所以就删除了。
知道原因解决就简单了: synchronized两个操作就可以了
网友评论