Android開發——MediaProvider原始碼分析(1)
http://www.cnblogs.com/halzhang/archive/2011/03/07/1976178.html
--------------START------------
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中有個廣播接收者,程式碼如下:
1: private BroadcastReceiver mUnmountReceiver = new BroadcastReceiver() {
2: @Override
3: public void onReceive(Context context, Intent intent) {
4: if (intent.getAction().equals(Intent.ACTION_MEDIA_EJECT)) {
5: // Remove the external volume and then notify all cursors backed by
6: // data on that volume
7: detachVolume(Uri.parse("content://media/external"));
8: sFolderArtMap.clear();
9: MiniThumbFile.reset();
10: }
11: }
12: };
此接收者是用來接收Sdcard解除安裝的廣播。當Sdcard從手機中分離出來的時候,Sdcard中的媒體檔案相對應的資料庫將無法操作。
1: private void detachVolume(Uri uri) {
2: //判斷是否是同一個程式
3: if (Process.supportsProcesses() && Binder.getCallingPid() != Process.myPid()) {
4: throw new SecurityException(
5: "Opening and closing databases not allowed.");
6: }
7: //此方法只是操作Sdcard的媒體資料庫,不支援手機記憶體的媒體資料庫
8: String volume = uri.getPathSegments().get(0);
9: if (INTERNAL_VOLUME.equals(volume)) {
10: throw new UnsupportedOperationException(
11: "Deleting the internal volume is not allowed");
12: } else if (!EXTERNAL_VOLUME.equals(volume)) {
13: throw new IllegalArgumentException(
14: "There is no volume named " + volume);
15: }
16:
17: synchronized (mDatabases) {
18: DatabaseHelper database = mDatabases.get(volume);
19: if (database == null) return;
20:
21: try {
22: // touch the database file to show it is most recently used
23: File file = new File(database.getReadableDatabase().getPath());
24: file.setLastModified(System.currentTimeMillis());
25: } catch (SQLException e) {
26: Log.e(TAG, "Can't touch database file", e);
27: }
28: //移除資料庫
29: mDatabases.remove(volume);
30: database.close();
31: }
32:
33: getContext().getContentResolver().notifyChange(uri, null);
34: if (LOCAL_LOGV) Log.v(TAG, "Detached volume: " + volume);
35: }
注意移除資料庫並非刪除資料庫檔案(*.db),mDatabases是一個HashMap<String,DatabaseHelper>,移除的含義是暫時無法操作,也可以說說是查詢返回的資料都是空的。
2.MediaScannerCursor
一個自定義遊標,用來查詢媒體檔案的掃描狀態。主要有一個volume欄位,用來區分是內建媒體資料庫還是Sdcard的媒體資料庫。
3.MediaScannerReceiver
此類實現廣播接收者。接收到廣播的時候對手機的媒體檔案進行掃描。
1: public class MediaScannerReceiver extends BroadcastReceiver
2: {
3: private final static String TAG = "MediaScannerReceiver";
4:
5: @Override
6: public void onReceive(Context context, Intent intent) {
7: String action = intent.getAction();
8: Uri uri = intent.getData();
9: String externalStoragePath = Environment.getExternalStorageDirectory().getPath();
10: //系統啟動完畢
11: if (action.equals(Intent.ACTION_BOOT_COMPLETED)) {
12: // scan internal storage
13: scan(context, MediaProvider.INTERNAL_VOLUME);
14: } else {
15: if (uri.getScheme().equals("file")) {
16: // handle intents related to external storage
17: String path = uri.getPath();
18: if (action.equals(Intent.ACTION_MEDIA_MOUNTED/*Sdcard掛載廣播*/) &&
19: externalStoragePath.equals(path)) {
20: scan(context, MediaProvider.EXTERNAL_VOLUME);
21: } else if (action.equals(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE/*單個檔案掃描廣播*/) &&
22: path != null && path.startsWith(externalStoragePath + "/")) {
23: scanFile(context, path);
24: }
25: }
26: }
27: }
掃描分為兩種三種情況:
a,啟動完畢掃面手機記憶體中的媒體檔案
b.sdcard掛載完畢掃描擴充套件卡的媒體檔案
c,掃描單個檔案
應用例項:我們可以傳送不同的廣播讓系統去掃描媒體檔案。當需要掃描單個檔案的時候需要設定一些引數,如下:
1: /**
2: * 掃描檔案
3: *
4: * @param filePath 檔案路徑
5: * @author http://t.sina.com.cn/halzhang
6: */
7: public void scanOneFile(final String filePath) {
8: Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
9: Uri uri = Uri.parse("file://" + filePath);
10: intent.setData(uri);
11: sendBroadcast(intent);
12: }
接著看一下scan和scenFile兩個方法:
1: private void scan(Context context, String volume/*內建卡或者外接卡*/) {
2: Bundle args = new Bundle();
3: args.putString("volume", volume);
4: context.startService(
5: new Intent(context, MediaScannerService.class).putExtras(args));
6: }
7:
8: private void scanFile(Context context, String path/*檔案路徑*/) {
9: Bundle args = new Bundle();
10: args.putString("filepath", path);
11: context.startService(
12: new Intent(context, MediaScannerService.class).putExtras(args));
13: }
兩個方法都是啟動MediaScannerService去掃描媒體檔案的。
關於MediaScannerSerive且聽下回分解。
-------------------END--------------
相關文章
- Android開發——MediaProvider原始碼分析(2)AndroidIDE原始碼
- Android開發Handler原始碼分析Android原始碼
- iOS開發原始碼閱讀篇--FMDB原始碼分析1(FMResultSet)iOS原始碼
- Android開發AsyncTask原始碼分析【模板方法模式】Android原始碼模式
- Android開源原始碼分析Android原始碼
- Android 原始碼分析之旅3 1 訊息機制原始碼分析Android原始碼
- Android 系統原始碼-1:Android 系統啟動流程原始碼分析Android原始碼
- 集合原始碼分析[1]-Collection 原始碼分析原始碼
- Android 原始碼分析之 AsyncTask 原始碼分析Android原始碼
- Android View 事件分發原始碼分析AndroidView事件原始碼
- 【Android原始碼】Fragment 原始碼分析Android原始碼Fragment
- 【Android原始碼】Intent 原始碼分析Android原始碼Intent
- Android開發Message原始碼分析【享元模式|物件池】Android原始碼模式物件
- 【Android原始碼】AlertDialog 原始碼分析Android原始碼
- Android 開源專案PhotoView原始碼分析AndroidView原始碼
- Leveldb原始碼分析--1原始碼
- MYSQL原始碼分析1MySql原始碼
- Android 常用開發工具類原始碼Android原始碼
- Android 開源專案原始碼解析 -->Android Universal Image Loader 原始碼分析(十四)Android原始碼
- Android Choreographer 原始碼分析Android原始碼
- Android RecycleView原始碼分析AndroidView原始碼
- Android——Handler原始碼分析Android原始碼
- 【Android原始碼】Handler 機制原始碼分析Android原始碼
- ecshop 二次開發,原始碼分析原始碼
- linux原始碼分析1Linux原始碼
- iOS開發原始碼閱讀篇--FMDB原始碼分析2(FMResultSet)iOS原始碼
- 使用eclipse來開發Android原始碼EclipseAndroid原始碼
- Android 原始碼分析之 EventBus 的原始碼解析Android原始碼
- Android原始碼分析--CircleImageView 原始碼詳解Android原始碼View
- Android中IntentService原始碼分析AndroidIntent原始碼
- 【Android原始碼】LayoutInflater 分析Android原始碼
- Android JiaoZiVideoPlayer原始碼分析AndroidIDE原始碼
- Android的AsyncTask原始碼分析Android原始碼
- Android SharedPreferences 原始碼分析Android原始碼
- android view layout原始碼分析AndroidView原始碼
- Android 原始碼結構分析Android原始碼
- Android Volley原始碼分析Android原始碼
- 原始碼分析系列1:HashMap原始碼分析(基於JDK1.8)原始碼HashMapJDK