1. 简介

MediaScannerService简称MSS, 是一个运行于后台的Service, 实现了Runnable接口.
MediaScannerReceiver接收广播, 然后由MSS具体完成工作. MSS中主要工作在ServiceHandler实现

2. 初始化

2.1 onCreate()

完成2项工作
(1)启动线程

        // Start up the thread running the service.  Note that we create a        // separate thread because the service normally runs in the process's        // main thread, which we don't want to block.        Thread thr = new Thread(null, this, "MediaScannerService");        thr.start();

之后会调用run方法, 参见2.2
(2) 注册/监听SDCard 卸载事件

        IntentFilter filter = new IntentFilter(Intent.ACTION_MEDIA_EJECT);        filter.addDataScheme("file");        filter.setPriority(100);        registerReceiver(mUnmountReceiver, filter);

2.2 run

MSS实现Runable的run方法, onCreate时会调用此方法启动线程.
run方法主要功能就是启动ServiceHandler

    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();    }

2.3 onStartCommand

(1) 等待ServiceHandler启动

        while (mServiceHandler == null) {            synchronized (this) {                try {                    wait(100);                } catch (InterruptedException e) {                    MtkLog.e(TAG, "onStartCommand: InterruptedException!");                }            }        }

(2) 处理Intent消息

        Bundle arguments = intent.getExtras();        int what;        if (arguments.getString("filepath") != null) {            what = MSG_SCAN_SINGLE_FILE;        } else if ( arguments.getString( "thumbPath" ) != null ) {            Log.d( TAG, "get do extract thumb action " );            what = MSG_EXTRACT_THUMBNAILS;        } else {            what = MSG_SCAN_DIRECTORY;        }

(3) 把消息传给ServiceHandler

        Message msg = mServiceHandler.obtainMessage(what, startId, -1, arguments);        mServiceHandler.sendMessage(msg);

2.4 onBind

    @Override    public IBinder onBind(Intent intent)    {        return mBinder;    }    private final IMediaScannerService.Stub mBinder =             new IMediaScannerService.Stub() {        public void requestScanFile(String path, String mimeType, IMediaScannerListener listener)        {            if (false) {                Log.d(TAG, "IMediaScannerService.scanFile: " + path + " mimeType: " + mimeType);            }            Bundle args = new Bundle();            args.putString("filepath", path);            args.putString("mimetype", mimeType);            if (listener != null) {                args.putIBinder("listener", listener.asBinder());            }            startService(new Intent(MediaScannerService.this,                    MediaScannerService.class).putExtras(args));        }        public void scanFile(String path, String mimeType) {            requestScanFile(path, mimeType, null);        }    };

3. ServiceHandler

处理2中类型
文件夹:
scan(directories, volume);
文件:
uri = scanFile(filePath, arguments.getString(“mimetype”));

private final class ServiceHandler extends Handler    {        @Override        public void handleMessage(Message msg)        {            Bundle arguments = (Bundle) msg.obj;            String filePath = arguments.getString("filepath");            try {                if (filePath != null) {                    IBinder binder = arguments.getIBinder("listener");                    IMediaScannerListener listener =                             (binder == null ? null : IMediaScannerListener.Stub.asInterface(binder));                    Uri uri = null;                    try {                        uri = scanFile(filePath, arguments.getString("mimetype"));                    } catch (Exception e) {                        Log.e(TAG, "Exception scanning file", e);                    }                    if (listener != null) {                        listener.scanCompleted(filePath, uri);                    }                } else {                    String volume = arguments.getString("volume");                    String[] directories = null;                    if (MediaProvider.INTERNAL_VOLUME.equals(volume)) {                        // scan internal media storage                        directories = new String[] {                                Environment.getRootDirectory() + "/media",                                Environment.getOemDirectory() + "/media",                        };                    }                    else if (MediaProvider.EXTERNAL_VOLUME.equals(volume)) {                        // scan external storage volumes                        directories = mExternalStoragePaths;                    }                    if (directories != null) {                        if (false) Log.d(TAG, "start scanning volume " + volume + ": "                                + Arrays.toString(directories));                        scan(directories, volume);                        if (false) Log.d(TAG, "done scanning volume " + volume);                    }                }            } catch (Exception e) {                Log.e(TAG, "Exception in handleMessage", e);            }            stopSelf(msg.arg1);        }    };}

4. scanFile & scan

scanFile 和scan 逻辑上基本相同, 都是调用framworks/base/media/java/android/media/MediaScanner.java完成具体工作

4.1 createMediaScanner

framworks/base/media/java/android/media/MediaScanner.java

    private MediaScanner createMediaScanner() {        MediaScanner scanner = new MediaScanner(this);        Locale locale = getResources().getConfiguration().locale;        if (locale != null) {            String language = locale.getLanguage();            String country = locale.getCountry();            String localeString = null;            if (language != null) {                if (country != null) {                    scanner.setLocale(language + "_" + country);                } else {                    scanner.setLocale(language);                }            }            }        return scanner;    }

4.2 scanFile

核心:
scanner.scanSingleFile(canonicalPath, volumeName, mimeType);

    private Uri scanFile(String path, String mimeType) {        String volumeName = MediaProvider.EXTERNAL_VOLUME;        openDatabase(volumeName);        MediaScanner scanner = createMediaScanner();        try {            // make sure the file path is in canonical form            String canonicalPath = new File(path).getCanonicalPath();            return scanner.scanSingleFile(canonicalPath, volumeName, mimeType);        } catch (Exception e) {            Log.e(TAG, "bad path " + path + " in scanFile()", e);            return null;        }    }

4.3 scan

核心语句
scanner.scanDirectories(directories, volumeName);

    private void scan(String[] directories, String volumeName) {        Uri uri = Uri.parse("file://" + directories[0]);        // don't sleep while scanning        mWakeLock.acquire();        try {            ContentValues values = new ContentValues();            values.put(MediaStore.MEDIA_SCANNER_VOLUME, volumeName);            Uri scanUri = getContentResolver().insert(MediaStore.getMediaScannerUri(), values);            sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_STARTED, uri));            try {                if (volumeName.equals(MediaProvider.EXTERNAL_VOLUME)) {                    openDatabase(volumeName);                }                MediaScanner scanner = createMediaScanner();                scanner.scanDirectories(directories, volumeName);            } catch (Exception e) {                Log.e(TAG, "exception in MediaScanner.scan()", e);            }            getContentResolver().delete(scanUri, null, null);        } finally {            sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_FINISHED, uri));            mWakeLock.release();        }    }

更多相关文章

  1. Android(安卓)Studio第三十八期 - HIOS跳转协议解决URI跳转原生
  2. Android中拍照、图片、录音、视频和音频功能的方法和代码
  3. Android运行main方法后java虚拟机停止运行
  4. android:屏幕自适应
  5. Android实现发送短信功能实例详解
  6. Android软键盘弹出时把布局顶上去,控件乱套解决方法
  7. Android(安卓)studio 启动模拟器时解决 VT-x is disabled in BIO
  8. 浅谈Java中Collections.sort对List排序的两种方法
  9. Python list sort方法的具体使用

随机推荐

  1. Android个人所得税计算器
  2. Android(安卓)4编程入门经典
  3. Android支持的媒体格式
  4. Android(安卓)Wifi模块分析(一)
  5. android播放网络音频
  6. 在Android中解析ls 命令得到目录列表的方
  7. android下大文件分割上传
  8. android 单元测试cmd 命令集
  9. 【Android】Navigation初试-官方demo分析
  10. 如何将android(gingerbread)源码导入eclips