田海立@csdn

2012-05-19

本文分析MediaScanner对单个文件的扫描过程。单个文件的扫描是MediaScanner的基础,对路径的扫描也要用到对Media文件的扫描。本文从MediaScannerService的scanFile入口开始,详细分析了MediaScanner和MediaScannerClient对单个媒体文件的扫描处理过程。

一、MediaScannerService.scanFile()


上文对MediaScannerService的分析,知道对单个文件的扫描是调用MediaScannerService.scanFile()完成的。下面看scanFile()的实现:


scanFile()中判断如果是外部媒体文件(只扫描外部媒体文件),创建MediaScanner(定义在frameworks/base/media/java/android/media)实例,并设置locale信息,然后调用MediaScanner的scanSingleFile()开始扫描。


二、MediaScanner.scanSingleFile()

MediaScanner.scanSingleFile()是具体的实现。看它完成的工作:


顺序执行了

  • initialize(); 3.1节中讲解该方法的工作;
  • prescan(); 3.2节中讲解该方法的工作;
  • MyMediaScannerClient.doScanFile() 3.3节中讲解该方法的工作。

下面分章节着重讲解这些方法里面都做了哪些工作。


三、MediaScanner


位于/framework/base/media/java/android/media/。


3.1 MediaScanner.initialize(volumeName: String)

initialize()对MediaScanner的MediaProvider/Audio/Video/Image等媒体库的URI进行初始化获取,要获取的属性有下面这些:


另外,如果扫描的是外部volume,要处理playlist和genre,所以mProcessPlaylists和mProcessGenres被设置为true;创建mGenreCache;获取Genres和playlists的URI。


3.2 MediaScanner.prescan()

  1. 从Audio、Video和Image各自的数据库中分别读取出这些媒体文件信息(ID,Path, Modified time),写入mFileCache: HashMap<String,FileCacheEntry>中;
  2. 从Playlist数据库中读取出播放列表文件信息(ID,Path, Modified time),写入mFileCache: HashMap<String,FileCacheEntry>中;

注意:新创建的FileCacheEntry的mSeenInFileSystem缺省值为false。


3.3 MyMediaScannerClient.doScanFile()

MyMediaScannerClient是MediaScanner的内部类,实现了MediaScannerClient。


MyMediaScannerClient提供了doScanFile()方法供外部调用。另外实现了MediaScannerClient这个Interface,这个Interface在JNI实现中非常重要,讲到那里时再详细阐述。

  • doScanFile()中调用beginFile(),获取FileType和MimeType信息,并初始化内部结构;
  • 如果返回了FileCacheEntry,并且不是Image文件,调用JNI方法processFile()解析到具体的文件信息在MyMediaScannerClient中;
  • 调用endFile()做后续的媒体库更新等处理。

3.3.1 beginFile()

参数:path:String; mimeType: String; lastModified: long, fileSize: long

  1. 用MediaFile获取FileType和MimeType,并分别赋值给mFileType和mMimeType;
  2. 从mFileCache中获取(文件已经在数据库中了:3.2preScan()中已经把数据库中的文件都写入到mFileCache),或生成新的entry:FileCacheEntry,加入到mFileCache中;
  3. 设置entry:FileCacheEntry的属性mSeenInFileSystem为 true【扫描到了该文件】;
  4. 如果是播放列表文件,加入到mPlaylists:ArrayList<FileCacheEntry>中,并直接返回null;
  5. 为MyMediaScannerClient中的各个属性(mArtist/ mAlbum / Artist / mAlbum / mTitle / mComposer / mGenre / mTrack / mYear /mDuration / mWriter / mCompliation)赋初值,为mPath / mLastModified赋值。返回 2)生成的FileCacheEntry的实例。

3.3.2 processFile()

JNI调用。详细分析在文//TODO中。

3.3.3 endFile(entry: FileCacheEntry, …)

  • 1) 根据mFileType(Audio/Video/Images),选择不同的数据库,并把相应的URI赋值给entry.mTableUri;
  • 2) 写入values:ContentValues信息
    • ①分别用MediaScannerClient中的下面各个属性值,初始化values:

    • MediaStore.MediaColumns.DATA: mPath
    • MediaStore.MediaColumns.TITLE: mTitle
    • MediaStore.MediaColumns.DATE_MODIFIED: mLastModifed
    • MediaStore.MediaColumns.SIZE: mFileSize
    • MediaStore.MediaColumns.MIME_TYPE: mMimeType
    • 对于Video文件

    oMediaStore.MediaColumns.ARTIST: mArtist/MediaStore.UNKNOWN_STRING

    oMediaStore.MediaColumns.ALBUM: mAlbum/ MediaStore.UNKNOWN_STRING

    oMediaStore.MediaColumns.DURATION: mDuration

    • 对于Audio文件

    oMediaStore.MediaColumns.ARTIST: mArtist/MediaStore.UNKNOWN_STRING

    oMediaStore.MediaColumns.ALBUM_ARTIST: mAlbumArtist/MediaStore.UNKNOWN_STRING

    oMediaStore.MediaColumns.ALBUM: mAlbum/ MediaStore.UNKNOWN_STRING

    oMediaStore.MediaColumns.COMPOSER: mComposer

    oMediaStore.MediaColumns.YEAR: mYear

    oMediaStore.MediaColumns.TRACK: mTrack

    oMediaStore.MediaColumns.DURATION: mDuration

    oMediaStore.MediaColumns.COMPILATION: mCompilation

      • ②对Title和Album做特殊处理
        • 如果Title为空,从MediaStore.MediaColumns.DATA:mPath 中分离出文件名(不含路径和后缀名),赋到value的MediaStore.MediaColumns.TITLE里;
        • 如果Album为MediaStore.UNKNOWN_STRING也就是文件中不含有Album信息,把MediaStore.MediaColumns.DATA:mPath 的父目录名赋到value的MediaStore.MediaColumns.ALBUM里。

      • ③对于Audio和JPG文件做一些特殊处理

      新加入的Audio,写入下列信息:

      • MediaStore.Audio.Media.IS_RINGTONE: ringtones
      • MediaStore.Audio.Media.IS_NOTIFICATION: notifications
      • MediaStore.Audio.Media.IS_ALARM: alarms
      • MediaStore.Audio.Media.IS_MUSIC: music
      • MediaStore.Audio.Media.IS_PODCAST: podcasts

      对于JPG文件,用android.media.ExifInterface获得下列信息:

      • MediaStore.Images.Media.LATITUDE;
      • MediaStore.Images.Media.LONGTITUDE;
      • MediaStore.Images.Media.DATE_TAKEN: gps dateTime;
      • MediaStore.Images.Media.ORIENTATION。

      • 3) 用2)中的values添加或更新1) 中URI指向的Audio/Video/Images数据库
      • 4) 如果要处理Genres(判断标志mProcessGenres,外部媒体都要处理),

        1. 用Genre的名字mGenre查询Genres的数据库,更新或插入一条由把mGenre赋给MediaStore.Audio.Genres.NAME字段组成的记录到MediaStore.Audio.Genres数据库中,并返回URI;
        2. 把 {genre, MediaStore.Audio.Genres.Members.CONTENT_DIRECTORY}加入mGenreCache:HashMap<String, Uri>中;
        3. 当前文件所在媒体库中的rowId赋值给MediaStore.Audio.Genres.Members.AUDIO_ID字段,组成一条记录插入到MediaStore.Audio.Genres.Members数据库中。

      更新一个媒体文件所属的Genre,需要更新Genres数据库,和Genres数据库对应的记录所在的Genres.Members数据库。

      • 5) 对notification/ringtone/alarm进行处理
      • 如果是notification/ringtone/alarm,并且还未设置notification/ringtone/alarm,那么设置Settings.System的Settings.System.NOTIFICATION_SOUND/ RINGTONE / ALARM_ALERT为媒体数据库的Uri形式。

      • 6) 返回媒体数据库的Uri。

      更多相关文章

      1. SpringBoot 2.0 中 HikariCP 数据库连接池原理解析
      2. 有关JDK,tomcat,android sdk+MyEclipse+adt 配置
      3. android中SQLite使用查看
      4. Android(安卓)studio 使用ndk开发JNI
      5. Android(安卓)SugarORM(1)
      6. 第五章 Android加载PDF文件的使用
      7. 记录----编译libyuv、迁移至Android(安卓)studio的操作和遇到的
      8. Android适配之dimens适配终极攻略(实际项目中应用方案)
      9. Android(安卓)两个Activity之间传值

      随机推荐

      1. android源代码在线查看
      2. Android画图学习总结
      3. (推荐)Android最全开发资源(转)
      4. 布局与样式
      5. Android强行进阶—按键事件&焦点事件攻略
      6. Android 自定义对话框去除白色边框代码
      7. Android第三课 联调华为手机
      8. Android之-异步消息处理机制
      9. Android里面编写退出主程序的提示代码
      10. Android 中的ListView选中项的背景颜色怎