MediaProvider包括五個類:
* com.android.providers.media.MediaProvider
* com.android.providers.media.MediaScannerCursor
* com.android.providers.media.MediaScannerReceiver
* com.android.providers.media.MediaScannerService
* com.android.providers.media.MediaThumbRequest
1.MediaProvider
此類繼承ContentProvider,實現一個內容提供者。主要用於建立媒體庫的資料庫表。有自己建立過ContentProvider的同學相信都比較清楚的。
特別說明一下在MediaProvider中有個廣播接收者,代碼如下:
private BroadcastReceiver mUnmountReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { if (intent.getAction().equals(Intent.ACTION_MEDIA_EJECT)) { // Remove the external volume and then notify all cursors backed by // data on that volume detachVolume(Uri.parse("content://media/external")); sFolderArtMap.clear(); MiniThumbFile.reset(); } } };
此接收者是用來接收Sdcard卸載的廣播。當Sdcard從手機中分離出來的時候,Sdcard中的媒體檔案相對應的資料庫將無法操作。
private void detachVolume(Uri uri) { //判斷是否是同一個進程 if (Process.supportsProcesses() && Binder.getCallingPid() != Process.myPid()) { throw new SecurityException( "Opening and closing databases not allowed."); } //此方法只是操作Sdcard的媒體資料庫,不支援手機記憶體的媒體資料庫 String volume = uri.getPathSegments().get(0); if (INTERNAL_VOLUME.equals(volume)) { throw new UnsupportedOperationException( "Deleting the internal volume is not allowed"); } else if (!EXTERNAL_VOLUME.equals(volume)) { throw new IllegalArgumentException( "There is no volume named " + volume); } synchronized (mDatabases) { DatabaseHelper database = mDatabases.get(volume); if (database == null) return; try { // touch the database file to show it is most recently used File file = new File(database.getReadableDatabase().getPath()); file.setLastModified(System.currentTimeMillis()); } catch (SQLException e) { Log.e(TAG, "Can't touch database file", e); } //移除資料庫 mDatabases.remove(volume); database.close(); } getContext().getContentResolver().notifyChange(uri, null); if (LOCAL_LOGV) Log.v(TAG, "Detached volume: " + volume); }
注意移除資料庫並非刪除資料庫檔案(*.db),mDatabases是一個HashMap,移除的含義是暫時無法操作,也可以說說是查詢返回的資料都是空的。
2.MediaScannerCursor
一個自訂遊標,用來查詢媒體檔案的掃描狀態。主要有一個volume欄位,用來區分是內建媒體資料庫還是Sdcard的媒體資料庫。
3.MediaScannerReceiver
此類實現廣播接收者。接收到廣播的時候對手機的媒體檔案進行掃描。
public class MediaScannerReceiver extends BroadcastReceiver { private final static String TAG = "MediaScannerReceiver"; @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); Uri uri = intent.getData(); String externalStoragePath = Environment.getExternalStorageDirectory().getPath(); //系統啟動完畢 if (action.equals(Intent.ACTION_BOOT_COMPLETED)) { // scan internal storage scan(context, MediaProvider.INTERNAL_VOLUME); } else { if (uri.getScheme().equals("file")) { // handle intents related to external storage String path = uri.getPath(); if (action.equals(Intent.ACTION_MEDIA_MOUNTED/*Sdcard掛載廣播*/) && externalStoragePath.equals(path)) { scan(context, MediaProvider.EXTERNAL_VOLUME); } else if (action.equals(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE/*單個檔案掃描廣播*/) && path != null && path.startsWith(externalStoragePath + "/")) { scanFile(context, path); } } } }
掃描分為兩種三種情況:
a,啟動完畢掃面手機記憶體中的媒體檔案
b.sdcard掛載完畢掃描擴充卡的媒體檔案
c,掃描單個檔案
應用執行個體:我們可以發送不同的廣播讓系統去掃描媒體檔案。當需要掃描單個檔案的時候需要設定一些參數,如下:
/** * 掃描檔案 * * @param filePath 檔案路徑 * @author http://t.sina.com.cn/halzhang */ public void scanOneFile(final String filePath) { Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE); Uri uri = Uri.parse("file://" + filePath); intent.setData(uri); sendBroadcast(intent); }
/** * update by Peng on 2011-10-18 */ //send a broadcast to mediascanner so that the music player can get the latest playlist if(mContext!=null){ Intent intent=new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE); Uri uri=Uri.parse("file:///mnt"+destFile.getAbsolutePath()); intent.setData(uri); mContext.sendBroadcast(intent); }//或者 context.sendBroadcast(new Intent( Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.parse("file://" + path)));//其中的path為絕對路徑,如:/mnt/sdcard/filename。
接著看一下scan和scenFile兩個方法:
private void scan(Context context, String volume/*內建卡或者外置卡*/) { Bundle args = new Bundle(); args.putString("volume", volume); context.startService( new Intent(context, MediaScannerService.class).putExtras(args)); } private void scanFile(Context context, String path/*檔案路徑*/) { Bundle args = new Bundle(); args.putString("filepath", path); context.startService( new Intent(context, MediaScannerService.class).putExtras(args)); }
兩個方法都是啟動MediaScannerService去掃描媒體檔案的。
關於MediaScannerSerive且聽下回分解。