上一次我们只是研究了一下Gallery3d的大致情况,发现了一些问题,就是什么时候发出开始扫描信息的和何时扫描的处理没有找到。
我们不得不扩大研究范围了,开始看在package\provider\mediaprovider,否则我们理解不了上述疑问。
mediaprovider 也是一个相关的APK,这个应用是对多媒体相关应用提供支持,如gallery3D music camera.
为什么要把扫描放在这里呢?因为多媒体的文件是多个应用处理的,每个应用都去扫描一遍是不是很浪费资源啊?对吧,再说每个应用扫描的数据库都保存一份也很浪费空间啊。
那么我们来简要的看下他的内容。
(使用的是android 4.2的mediaprovider ,因手头只有4.*的mediaprovider,研究的内容或许和2.3有些差别)
<receiver android:name="MediaScannerReceiver"> <intent-filter> <action android:name="android.intent.action.BOOT_COMPLETED" /> </intent-filter> <intent-filter> <action android:name="android.intent.action.MEDIA_MOUNTED" /> <data android:scheme="file" /> </intent-filter> <intent-filter> <action android:name="android.intent.action.MEDIA_UNMOUNTED" /> <data android:scheme="file" /> </intent-filter> <intent-filter> <action android:name="android.intent.action.MEDIA_SCANNER_SCAN_FILE" /> <data android:scheme="file" /> </intent-filter> </receiver>
我们看到了上面这个receiver,这里注册了
四种情况,我们再在MediaScannerReceiver中看他的处理
@Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); Uri uri = intent.getData(); if (action.equals(Intent.ACTION_BOOT_COMPLETED)) { // scan internal storage scan(context, MediaProvider.INTERNAL_VOLUME); } else { if (uri.getScheme().equals("file")) { // handle intents related to external storage String path = uri.getPath(); String externalStoragePath = Environment.getExternalStorageDirectory().getPath(); Log.d(TAG, "action: " + action + " path: " + path); if (action.equals(Intent.ACTION_MEDIA_MOUNTED)) { // scan whenever any volume is mounted scan(context, MediaProvider.EXTERNAL_VOLUME); } else if (action.equals(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE) && path != null && path.startsWith(externalStoragePath + "/")) { scanFile(context, path); } } } }
那么说明开机就会全部扫描内部存储器,外部存储器挂载时也会扫描,另外还可以主动要求扫描某个文件。
(谁会主动发起文件扫描呢?比如彩信接受到一个图片存在一个地方,这个时候想让图库扫描到,可以使用
SendBroadcast(new Intent(Intent,ACTION_MEDIA_SCANNER_SCAN_FILE,uri)); 主动让图库扫描到。)
扫描的发起我们都弄清楚了,看下怎么扫描的。
private void scan(Context context, String volume) { Bundle args = new Bundle(); args.putString("volume", volume); context.startService( new Intent(context, MediaScannerService.class).putExtras(args)); } private void scanFile(Context context, String path) { Bundle args = new Bundle(); args.putString("filepath", path); context.startService( new Intent(context, MediaScannerService.class).putExtras(args)); }
那么扫描内部是怎么处理的呢?我们在MediaScannerService.java中学习
@Override public void onCreate() { PowerManager pm = (PowerManager)getSystemService(Context.POWER_SERVICE); mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG); StorageManager storageManager = (StorageManager)getSystemService(Context.STORAGE_SERVICE); mExternalStoragePaths = storageManager.getVolumePaths(); // 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(); }
private void scan(String[] directories, String volumeName) { // don't sleep while scanning mWakeLock.acquire(); ContentValues values = new ContentValues(); values.put(MediaStore.MEDIA_SCANNER_VOLUME, volumeName); Uri scanUri = getContentResolver().insert(MediaStore.getMediaScannerUri(), values); Uri uri = Uri.parse("file://" + directories[0]); 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); sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_FINISHED, uri)); mWakeLock.release(); }
可能有人还想知道这里面到底是怎么扫描的
MediaScanner scanner = createMediaScanner(); scanner.scanDirectories(directories, volumeName);在framework/base/media/java/android/media的MediaScanner.java 有scanDirectories 中会继续调用Jni的接口到MediaScanner.cpp中去,实现就在里面。
再会调用到processDirectory中再通过递归调用doProcessDirectory来实现对目录和文件的枚举。
那么数据库在哪里呢?是怎么存储的呢?我们下个回合分解
参考文档
http://wenku.baidu.com/view/9151d3d349649b6648d747d2.html