您的位置:首页 > 移动开发 > Android开发

【转载】Android开发——MediaProvider源码分析(1)

2011-03-11 20:46 435 查看
转载自:/article/5845002.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[/code] 
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:     }


接着看一下scanscenFile两个方法:

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--------------
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: