小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

abdroid MediaScanner(2)

 浮云沫沫33 2013-09-06
Android MediaScanner:(三)MediaScannerService
        對MediaScannerService的類結(jié)構(gòu)進(jìn)行靜態(tài)分析,對創(chuàng)建時和啟動時的工作進(jìn)行動態(tài)分析,分析過程中來看MediaScannerService如何處理MediaScannerReceiver所接收到的各種掃描請求。

本文是筆者的分析歸納,并用UML圖(ClassDiagram/Sequence Diagram)來呈現(xiàn)。雖然來源于對Android源碼的分析,但文中不會占用大量篇幅羅列源碼,所以讀者在閱讀本文時,手頭最好有Android源碼,結(jié)合源碼來解讀。本文對MediaScannerService的類結(jié)構(gòu)進(jìn)行靜態(tài)分析,對創(chuàng)建時和啟動時的工作進(jìn)行動態(tài)分析,分析過程中來看MediaScannerService如何處理MediaScannerReceiver所接收到的各種掃描請求。

 

一、MediaScannerService的靜態(tài)結(jié)構(gòu)分析

MediaScanner_ClassDiagram

  •  MediaScannerService是一個Service,并實現(xiàn)Runnable,實現(xiàn)工作線程。
  •  MediaScannerService通過ServiceHandler這個Handler把主線程需要大量計算的工作放到工作線程中去做。

在Runnable.run()中執(zhí)行消息循環(huán),把通過Handler發(fā)送過來的消息在工作線程中執(zhí)行。


二、MediaScannerService的動態(tài)分析

        在MediaScannerService被通過startService啟動的過程中,其實包含了創(chuàng)建時的工作。下面分別分析創(chuàng)建時和啟動時所完成的工作。

2.1 創(chuàng)建之時#0nCreate()

Service對象在被創(chuàng)建的時候,onCreate()會被調(diào)用,看一下MediaScannerService的onCreate()里面做了什么:

  1. PowerManager pm = (PowerManager)getSystemService(Context.POWER_SERVICE);  
  2. mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,TAG);  
  3.    
  4. Thread thr = new Thread(nullthis, “MediaScannerService”);  
  5. Thr.start();  


MediaScannerService創(chuàng)建就是為了掃描Media的,這一過程是非常費時費力的。所以:

  •  為了防止在媒體掃描過程中,CPU睡死過去,用PowerManager的WakeLock告訴PowerManager,我這邊還在忙,別睡死了[Line#1,2];
  •  在Android的主線程中要快速返回,大量的計算任務(wù)交給工作線程去做,這里啟了一個工作線程,而這個線程的執(zhí)行體就是MediaScannerService所實現(xiàn)Runnable的run()方法,用Handler發(fā)消息之前,一定要先啟動該線程的[Line#4,5]。

2.2 Service啟動時#onStartCommand()

        Service對象在被啟動的時候,onStartCommand()會被調(diào)用,看一下MediaScannerService的onStartCommand()里面做了什么。


        下圖是MediaScannerService#onStartCommand()中完成的工作:

MediaScannerService_StartSequence

  •  通過參數(shù)startId和intent獲得的Bundle,通過mServiceHandler發(fā)送到工作線程中去執(zhí)行[Line#1~5];
  •  ServiceHandler的handleMessage()中,根據(jù)傳進(jìn)來不同的“filepath”、“volume”以及“folder”參數(shù),執(zhí)行不同的掃描工作[Line#6~11];
  •  掃描結(jié)束,MediaScannerService本次的使命也就完成,可以stop自身了[Line#12]。

  • 可以結(jié)合MediaScannerReceiver中啟動方式的不同來看傳入的參數(shù):

  •  如果有“filepath”,是要掃描某個文件,調(diào)用scanFile()。掃描單個文件如何實現(xiàn),在Android MediaScanner:(四)MediaScanner之scanSingleFile中講解。
  •  否則,無論是針對整個volume還是某個folder的掃描,都可歸結(jié)為對目錄的掃描:對內(nèi)部volume,掃描”system/media”;對外部volume,掃描整個“/mnt/sdcard”;對含有“folder”參數(shù)的,directories[]中只包含“folder”中的路徑。

三、小結(jié)

        本文對MediaScannerService的類結(jié)構(gòu)進(jìn)行了靜態(tài)分析,對創(chuàng)建時和啟動時的工作進(jìn)行了動態(tài)分析,分析過程中看MediaScannerService如何響應(yīng)MediaScannerReceiver所接收到的各種掃描請求。


與其他文章的關(guān)系:

  •  向前看MediaScannerReceiver,來自外部的掃描請求,啟動MediaScannerService,由Service來具體負(fù)責(zé)實現(xiàn);
  •  向后看MediaScanner才是真正的掃描實現(xiàn),分掃描文件掃描路徑來講解。

Android MediaScanner:(四)MediaScanner之scanSingleFile

        本文從MediaScannerService的scanFile入口開始,詳細(xì)分析MediaScanner和MediaScannerClient對單個媒體文件的掃描處理過程。

本文分析MediaScanner對單個文件的掃描過程。單個文件的掃描是MediaScanner的基礎(chǔ),對路徑的掃描也要用到對Media文件的掃描。本文從MediaScannerService的scanFile入口開始,詳細(xì)分析了MediaScanner和MediaScannerClient對單個媒體文件的掃描處理過程。

 

一、MediaScannerService.scanFile()


上文對MediaScannerService的分析,知道對單個文件的掃描是調(diào)用MediaScannerService.scanFile()完成的。下面看scanFile()的實現(xiàn):

MediaScannerService.scanFile

scanFile()中判斷如果是外部媒體文件(只掃描外部媒體文件),創(chuàng)建MediaScanner(定義在frameworks/base/media/java/android/media)實例,并設(shè)置locale信息,然后調(diào)用MediaScanner的scanSingleFile()開始掃描。


二、MediaScanner.scanSingleFile()

 

MediaScanner.scanSingleFile()是具體的實現(xiàn)。看它完成的工作:

MediaScanner.scanSingleFile

順序執(zhí)行了

  •  initialize(); 3.1節(jié)中講解該方法的工作;
  •  prescan(); 3.2節(jié)中講解該方法的工作;
  •  MyMediaScannerClient.doScanFile() 3.3節(jié)中講解該方法的工作。

下面分章節(jié)著重講解這些方法里面都做了哪些工作。


三、MediaScanner


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


 

3.1 MediaScanner.initialize(volumeName: String)

initialize()對MediaScanner的MediaProvider/Audio/Video/Image等媒體庫的URI進(jìn)行初始化獲取,要獲取的屬性有下面這些:

MediaScanner initialize properties

另外,如果掃描的是外部volume,要處理playlist和genre,所以mProcessPlaylists和mProcessGenres被設(shè)置為true;創(chuàng)建mGenreCache;獲取Genres和playlists的URI。


 

3.2 MediaScanner.prescan()

  1. 從Audio、Video和Image各自的數(shù)據(jù)庫中分別讀取出這些媒體文件信息(ID,Path, Modified time),寫入mFileCache: HashMap<String,FileCacheEntry>中;
  2. 從Playlist數(shù)據(jù)庫中讀取出播放列表文件信息(ID,Path, Modified time),寫入mFileCache: HashMap<String,FileCacheEntry>中;

注意:新創(chuàng)建的FileCacheEntry的mSeenInFileSystem缺省值為false。


3.3 MyMediaScannerClient.doScanFile()

MyMediaScannerClient是MediaScanner的內(nèi)部類,實現(xiàn)了MediaScannerClient。

MyMediaScannerClient

MyMediaScannerClient提供了doScanFile()方法供外部調(diào)用。另外實現(xiàn)了MediaScannerClient這個Interface,這個Interface在JNI實現(xiàn)中非常重要,講到那里時再詳細(xì)闡述。

  •  doScanFile()中調(diào)用beginFile(),獲取FileType和MimeType信息,并初始化內(nèi)部結(jié)構(gòu);
  •  如果返回了FileCacheEntry,并且不是Image文件,調(diào)用JNI方法processFile()解析到具體的文件信息在MyMediaScannerClient中;
  •  調(diào)用endFile()做后續(xù)的媒體庫更新等處理。

 

3.3.1 beginFile()

參數(shù):path:String; mimeType: String; lastModified: long, fileSize: long

  1.  用MediaFile獲取FileType和MimeType,并分別賦值給mFileType和mMimeType;
  2.  從mFileCache中獲?。ㄎ募呀?jīng)在數(shù)據(jù)庫中了:3.2preScan()中已經(jīng)把數(shù)據(jù)庫中的文件都寫入到mFileCache),或生成新的entry:FileCacheEntry,加入到mFileCache中;
  3.  設(shè)置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調(diào)用。詳細(xì)分析在文//TODO中。

3.3.3 endFile(entry: FileCacheEntry, …)

  • 1) 根據(jù)mFileType(Audio/Video/Images),選擇不同的數(shù)據(jù)庫,并把相應(yīng)的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文件

o  MediaStore.MediaColumns.ARTIST: mArtist/MediaStore.UNKNOWN_STRING

o  MediaStore.MediaColumns.ALBUM: mAlbum/ MediaStore.UNKNOWN_STRING

o  MediaStore.MediaColumns.DURATION: mDuration

  •  對于Audio文件

o  MediaStore.MediaColumns.ARTIST: mArtist/MediaStore.UNKNOWN_STRING

o  MediaStore.MediaColumns.ALBUM_ARTIST: mAlbumArtist/MediaStore.UNKNOWN_STRING

o  MediaStore.MediaColumns.ALBUM: mAlbum/ MediaStore.UNKNOWN_STRING

o  MediaStore.MediaColumns.COMPOSER: mComposer

o  MediaStore.MediaColumns.YEAR: mYear

o  MediaStore.MediaColumns.TRACK: mTrack

o  MediaStore.MediaColumns.DURATION: mDuration

o  MediaStore.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數(shù)據(jù)庫。
  • 4) 如果要處理Genres(判斷標(biāo)志mProcessGenres,外部媒體都要處理),

    1. 用Genre的名字mGenre查詢Genres的數(shù)據(jù)庫,更新或插入一條由把mGenre賦給MediaStore.Audio.Genres.NAME字段組成的記錄到MediaStore.Audio.Genres數(shù)據(jù)庫中,并返回URI;
    2. 把 {genre, MediaStore.Audio.Genres.Members.CONTENT_DIRECTORY}加入mGenreCache:HashMap<String, Uri>中;
    3. 當(dāng)前文件所在媒體庫中的rowId賦值給MediaStore.Audio.Genres.Members.AUDIO_ID字段,組成一條記錄插入到MediaStore.Audio.Genres.Members數(shù)據(jù)庫中。

更新一個媒體文件所屬的Genre,需要更新Genres數(shù)據(jù)庫,和Genres數(shù)據(jù)庫對應(yīng)的記錄所在的Genres.Members數(shù)據(jù)庫。

  • 5) 對notification/ringtone/alarm進(jìn)行處理
  • 如果是notification/ringtone/alarm,并且還未設(shè)置notification/ringtone/alarm,那么設(shè)置Settings.System的Settings.System.NOTIFICATION_SOUND/ RINGTONE / ALARM_ALERT為媒體數(shù)據(jù)庫的Uri形式。

  • 6) 返回媒體數(shù)據(jù)庫的Uri。

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多