美文网首页我爱编程
Android联系人头像存储流程

Android联系人头像存储流程

作者: 平头说人生 | 来源:发表于2018-06-21 22:17 被阅读63次

    有头像的联系人来电,界面不显示头像:

    1 查看头像保存流程:原图,剪切的方形图,保存的头像

    进入联系人编辑界面的ContactEditorFragment后
    ==》bindEditors
    ==》gernateRawContactView
    ==》bindPhotoHandler
    (
    初始化PhotoHandler:

       在PhotoHandler中初始化mTempPhotoUri和mCroppedPhotoUri
       当图片不是DrmImage的时候需要将原图读取到一个临时地方, mTempPhotoUri用来表示这个临时地方的uri
       如果是DrmImage或者拍摄的图片则直接使用原图的Uri: 其作用是作为剪切动作中的输入源。
       
       mCroppedPhotoUri是剪切动作中的输出源,将剪切好的图片放到该uri下面。
    )
    

    ==》拍摄的图片会放到content://com.android.contacts.files/my_cache/路径下,直接当作剪切图片输入源。
    选择的图片查看是否DrmImage,如果不是则先读取放到mTempPhotoUri,再作为剪切图片输入源,如果是则同上直接作为剪切图片的输入源

    ==》剪切后会放到mCroppedPhotoUri中,路径也是content://com.android.contacts.files/my_cache/

    ==》点击剪切,ContactEditorFragment.PhotoHandler.PhotoEditorListener.onPhotoSelected

    ==》setPhoto(....)
    (
    该函数会将剪切的头像的uri更新到mUpdatedPhotos中,如下
    (Bundlle)mUpdatedPhotos.putParcelable(String.valueOf(rawContact), photoUri);
    )

    ==》点击保存

    ==》start ContactSaveService

    ==》saveContact
    (
    先保存非头像数据拿到insertedRawContactId,
    然后从上面mUpdatedPhotos获取parceable数据photoUri,即存在content://com.android.contacts.files/my_cache/路径下的资源,
    ContactPhotoUtils.savePhotoFromUriToUri通过stream将头像数据写入db

    写入方式如下:
    outputUri= content://com.android.contacts/raw_contacts/34/display_photo
    getContentResolver()
                    .openAssetFileDescriptor(outputUri, "rw").createOutputStream(); 
        
    
    
        最后删除存在content://com.android.contacts.files/my_cache/路径下的photo资源
    )
    

    ==》到这里App端的保存动作结束,如果发生IO异常会导致头像保存失败。

    那么ContactsProvider是怎么将保存的图片放到/data/data/com.android.providers.contacts/files/目录下呢??

    App端调用openAssetFileDescriptor(outputUri, "rw")之后binder到ContactsProvider.openAssetFile
    =》openAssetFileLocal
    =》openAssetFileInner
    (
    在返回FileDescriptor之前会先查询传入的uri中的id是否有效,如果有效则代表存在有效的联系人,然后返回有效的descriptor
    如果无效则抛出异常。
    这说明头像的插入必须在联系人建立之后,这也是为什么上层App在存储完毕非头像数据后才去存储头像的原因。
    )

    =》创建ParcelFileDescriptor数组,个数为2,
    第一个用来读,封装成PipeMonitor(继承AsyncTask),
    第二个用来写,用来写的封装成AssetFileDescriptor(实现parceable接口)返回给用户,
    写入完毕后PipeMonitor在后台通过stream创建缩略图和原图。
    创建原图的时候先写入一个临时文件,等图片信息插入photo_files后,拿到返回的id,再将前面的临时文件重命名为id,
    至此我们就看到data/data/com.android.providers.contacts/files/photo/下面全是以数字命名的图片。

    =》到了这里联系人的头像就插入完毕了
    可以看出联系人头像插入失败的两个原因:
    原因一:联系人的非头像数据保存的时候失败,没有产生有效的rawContactId,导致后续插入头像数据的时候无有效id而异常。
    原因二:写入的时候IO异常

    2 查看头像读取流程:小头像读取,大头像读取,原图读取

    3 怀疑是剪切后的头像没有保存成功

    Wilson 头像拉伸问题:

    1 原图是非裁剪过的原图
    2 db里面存储的也是非裁剪过的图片

    疑问:

    为何联系人里面显示的是正确的?

    备注:
    头像大小的定义在ContactsProvider的下述文件中
    ContactsProvider/src/com/android/providers/contacts/PhotoProcessor.java
    定义了如下两个变量:
    sMaxThumbnailDim:缩略图大小,如果property值有定义contacts.thumbnail_size则取这个值,不然使用默认值96

    sMaxDisplayPhotoDim:大头像大小,如果property值有定义contacts.display_photo_size则取这个值,不然使用默认值,
    默认值根据手机内存大小决定,大于680M的手机使用720, 否则使用480

    发现的可优化点:
    1 拍摄的图片直接用原资源进行剪切,不用先存储到一个临时地方。
    2 去掉MTK相关的静态代码,从ContactsSystemProperties.java查起
    3 BaseRawContactEditorView.setState有耗时操作

    Debug信息:

    拍摄后拿到的Uri:
    content://com.android.contacts.files/my_cache/ContactPhoto-IMG_20180621_165824.jpg

    剪切时的信息:
    ClipData:
    ClipData { text/uri-list "output" {U:content://com.android.contacts.files/my_cache/ContactPhoto-IMG_20180621_165824-cropped.jpg} }

    mExtras:
    Bundle[{outputX=720, outputY=720, output=content://com.android.contacts.files/my_cache/ContactPhoto-IMG_20180621_165824-cropped.jpg, aspectX=1, aspectY=1, crop=true, scale=true, scaleUpIfNeeded=true}]

    mData :
    content://com.android.contacts.files/my_cache/ContactPhoto-IMG_20180621_165824.jpg

    待研究问题:
    1 需要研究下content://com.android.contacts.files/指向哪里

    2 研究下PipeMonitor是怎么监听pipe写入完毕的

    相关文章

      网友评论

        本文标题:Android联系人头像存储流程

        本文链接:https://www.haomeiwen.com/subject/ymfhyftx.html