android的多媒体扫描

来源:互联网 发布:vb crc教程 编辑:程序博客网 时间:2024/05/21 19:45

      Settings.system是保存手机的一些用户设置项,像飞行模式,铃声设置,保证关机后用户设置的数据还存在;SystemProperties是中保存着系统的配置属性,MediaStoreandroid系统提供的一个多媒体数据库,android中多媒体信息都可以从这里提取。这个MediaStore包括了多媒体数据库的所有信息,包括音频,视频和图像的路径和详细详细信息,android把所有的多媒体数据库接口进行了封装,所有的数据库不用自己进行创建,直接调用利用ContentResolver去掉用那些封装好的接口就可以进行数据库的操作MediaStore中的数据则是在android多媒体扫描的时候添加进数据库的,首先在/packages/providers/MediaProvider/src/com/android/providers/media/MediaScannerReceiver.java会接收到相应文件扫描的广播,然后根据相应的广播进行扫描,主要是处理三种Broardcast请求,也有厂商自己自定义自己系类的广播扫描方式


 BOOT_COMPLETED 系统启动之后,接到该Action调用  scan(context, MediaProvider.INTERNAL_VOLUME);和  scanUntilAllStorageMounted(context);将内部存储和外部存储的数据扫描到对应的数据库。
所以你在开发的时候,每次开模拟器或手机你注意Logcat信息,就可以发现:scanner Internal Volumn...等等相关信息
   
 MEDIA_MOUNTED 外部存储卡挂载之后,接到该Action调用scanUntilAllStorageMounted(context)扫描外部Media;
    
 MEDIA_SCANNER_SCAN_FILE 扫描某一个多媒体文件,接到该Action之后scanFile(context, path)(app端添加文件后发送广播,将相应的多媒体添加到数据库....);

但是不管是sscan(context, MediaProvider.INTERNAL_VOLUME); scanUntilAllStorageMounted(context);在或者scanFile(context, path)在MediaScannerReceiver中最后都通过context.startService(new Intent(context, MediaScannerService.class).putExtras(args));启动了MediaScannerService服务。

在packages/providers/MediaProvider/src/com/android/providers/media/MediaScannerService.java
继承了service实现了Runnable接口,在相应的run方法中
public void run()
    {
        Looper.prepare();

        mServiceLooper = Looper.myLooper();
        mServiceHandler = new ServiceHandler();

        /// M: reduce thread priority after ServiceHandler have been created to avoid cpu starvation
        /// which may cause ANR because create service handler too slow.
        // reduce priority below other background threads to avoid interfering
        // with other services at boot time.
        Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND + Process.THREAD_PRIORITY_LESS_FAVORABLE);

        Looper.loop();
}
在run方法中设置了线程的优先级,优先级比较低,主要为了避免跟其他服务抢夺资源。还有就是利用looper对ServiceHandler的消息进行循环控制。
每次在onStartCommand通过mServiceHandler刷新Handler 要发送的消息;
    public int onStartCommand(Intent intent, int flags, int startId)
    {
       ……….
        Message msg = mServiceHandler.obtainMessage(what, startId, -1, arguments);
        mServiceHandler.sendMessage(msg);

        // Try again later if we are killed before we can finish scanning.
        return Service.START_REDELIVER_INTENT;
    }

接着看一下ServiceHandler的实现代码:
private final class ServiceHandler extends Handler
    {
        @Override
        public void handleMessage(Message msg)
        {
            /// M: MediaScanner Performance turning {@
            /// Add two message for shutdown threadpool
            /// and handle scan finish request.
            MtkLog.v(TAG, "handleMessage: what = " + msg.what + ", startId = " + msg.arg1 + ", arguments = " + msg.obj);
            switch (msg.what) {
                case MSG_SCAN_SINGLE_FILE:
                    handleScanSingleFile(msg);
                    break;

                case MSG_SCAN_DIRECTORY:
                    handleScanDirectory(msg);
                    break;

                case MSG_SHUTDOWN_THREADPOOL:
                    handleShutdownThreadpool();
                    break;

                case MSG_SCAN_FINISH_WITH_THREADPOOL:
                    handleScanFinish();
                    break;

                default:
                    MtkLog.w(TAG, "unsupport message " + msg.what);
                    break;
            }
            /// @}
        }
    };
在相应的case中定义了不同的扫描方式和当扫描结束等情况;
但都没有对文件进行扫描,相应的走到了scanner.scanSingleFile(canonicalPath, volumeName, mimeType)或者  scanner.scanDirectories(directories, volumeName);或mPreScanner.postScanAll(mMediaScannerThreadPool.getPlaylistFilePaths());
最终都指向了frameworks/base/media/java/android/media/MediaScanner.java,都是MediaScanner中的方法。
在MediaScanner对上层隐藏了,用了@hide的注解,开始的静态代码块中
static {
        System.loadLibrary("media_jni");
        native_init();
    }
加载了media_jni库,做了jni本地方法的初始化,接着看MediaScannerService 调用的MediaScanner的scanDirectories和scanSingleFile完成最终的扫描的方法:
public void scanDirectories(String[] directories, String volumeName) {
        try {
            long start = System.currentTimeMillis();
            initialize(volumeName);
            prescan(null, true);
            long prescan = System.currentTimeMillis();

            if (ENABLE_BULK_INSERTS) {
                // create MediaInserter for bulk inserts
                mMediaInserter = new MediaInserter(mMediaProvider, mPackageName, 500);
            }

            for (int i = 0; i < directories.length; i++) {
                processDirectory(directories[i], mClient);
            }

            if (ENABLE_BULK_INSERTS) {
                // flush remaining inserts
                mMediaInserter.flushAll();
                mMediaInserter = null;
            }

            long scan = System.currentTimeMillis();
            postscan(directories);
            long end = System.currentTimeMillis();

分了initialize ,preScan和postScan三个函数
[java] view plaincopyprint?

    private void initialize(String volumeName) {  
        //打开MediaProvider,获得它的一个实例  
        mMediaProvider = mContext.getContentResolver().acquireProvider("media");  
        //得到一些uri  
        mAudioUri = Audio.Media.getContentUri(volumeName);  
        mVideoUri = Video.Media.getContentUri(volumeName);  
        mImagesUri = Images.Media.getContentUri(volumeName);  
        mThumbsUri = Images.Thumbnails.getContentUri(volumeName);  
        //外部存储的话,可以支持播放列表之类的东西,搞了一些个缓存池之类的  
        //如mGenreCache等  
        if (!volumeName.equals("internal")) {  
            // we only support playlists on external media  
            mProcessPlaylists = true;  
            mGenreCache = new HashMap<String, Uri>();  
            …  


preScan,这个函数很复杂:
大概就是创建一个FileCache,用来缓存扫描文件的一些信息,例如last_modified等。这个FileCache是从MediaProvider中已有信息构建出来的,也就是历史信息。后面根据扫描得到的新信息来对应更新历史信息。
postScan,这个函数做一些清除工作,例如以前有video生成了一些缩略图,现在video文件被干掉了,则对应的缩略图也要被干掉。另外还有一个mClient,这个是从MediaScannerClient派生下来的一个东西,里边保存了一个文件的一些信息。
具体扫描工作是在processDirectory函数中完成的。这个是一个native函数。
在frameworks\base\media\jni\android_media_MediaScanner.cpp中,和frameworks/av/media/libmedia/MediaScanner.cpp一番转转后将扫描结果返回上层在frameworks/base/media/java/android/media/MediaScanner.java中的handleStringTag解析的结果返回到上层应用。
0 0
原创粉丝点击