zoukankan      html  css  js  c++  java
  • Android开发——MediaProvider源码分析(1)

    转载请注明出处。

    --------------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:     }

    接着看一下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--------------

  • 相关阅读:
    Codeforces 691A Fashion in Berland
    HDU 5741 Helter Skelter
    HDU 5735 Born Slippy
    HDU 5739 Fantasia
    HDU 5738 Eureka
    HDU 5734 Acperience
    HDU 5742 It's All In The Mind
    POJ Euro Efficiency 1252
    AtCoder Beginner Contest 067 C
    AtCoder Beginner Contest 067 D
  • 原文地址:https://www.cnblogs.com/halzhang/p/1976178.html
Copyright © 2011-2022 走看看