源码分析MediaStore是怎么管理文件的(一)

Cursor cursor = getContentResolver().query(
                Uri.parse("content://media/external/file"),
                projection,
                MediaStore.Files.FileColumns.DATA + " not like ? and ("
                        + MediaStore.Files.FileColumns.DATA + " like ? or "
                        + MediaStore.Files.FileColumns.DATA + " like ? or "
                        + MediaStore.Files.FileColumns.DATA + " like ? or "
                        + MediaStore.Files.FileColumns.DATA + " like ? )",
                new String[]{"%" + bookpath + "%",
                        "%" + Constant.SUFFIX_TXT,
                        "%" + Constant.SUFFIX_PDF,
                        "%" + Constant.SUFFIX_EPUB,
                        "%" + Constant.SUFFIX_CHM}, null);

这是一段搜索media中后缀为txt,pdf,epub,chm格式的文档的源码.这里我们使用了一个内容URI"content://media/external/file/",然而这个URI究竟是在哪里呢?这是一个系统自带的一个内容URI,来自MediaPlayer.我们跟踪MediaPlayer的源码.

499        public static final Uri getContentUri(String volumeName) {
501            return Uri.parse(CONTENT_AUTHORITY_SLASH + volumeName
502                    + "/file/");
503        }

这里我们看到getContentUri方法返回了一个CONTENT_AUTHORITY_SLASH + volumeName + “/file/”,CONTENT_AUTHORITY_SLASH在类中已经定义了,
就是"media",那么volumeName代表的是什么呢,我们看到volumeName是作为参数传入的,因此我们搜索getContentUri方法,看看它都能传递什么参数,我们找到这么一行,

 public static final Uri EXTERNAL_CONTENT_URI =
1164                    getContentUri("external");

因此我们的内容URI确实是MediaPlayer提供的.并且在MediaPlayer类中组装成了EXTERNAL_CONTENT_URI,它的值就是"content://media/external/file",那么我们得到这个EXTERNAL_CONTENT_URI是做什么的呢?我们继续搜索,得到这么一段代码:

1072            public static final Cursor queryMiniThumbnail(ContentResolver cr, long origId, int kind,
1073                    String[] projection) {
1074                return cr.query(EXTERNAL_CONTENT_URI, projection,
1075                        IMAGE_ID + " = " + origId + " AND " + KIND + " = " +
1076                        kind, null, null);
1077            }

说明MediaStore利用这个EXTERNAL_CONTENT_URI来进行CRUD操作,并且是利用ContentResolver来进行查询的,我们跟踪ContentResolver,定位到query方法:

782    public final @Nullable Cursor query(final @RequiresPermission.Read @NonNull Uri uri,
783            @Nullable String[] projection, @Nullable Bundle queryArgs,
784            @Nullable CancellationSignal cancellationSignal) {
785        Preconditions.checkNotNull(uri, "uri");
786        IContentProvider unstableProvider = acquireUnstableProvider(uri);
787        if (unstableProvider == null) {
788            return null;
789        }
790        IContentProvider stableProvider = null;
791        Cursor qCursor = null;
792        try {
793            long startTime = SystemClock.uptimeMillis();
794
795            ICancellationSignal remoteCancellationSignal = null;
796            if (cancellationSignal != null) {
797                cancellationSignal.throwIfCanceled();
798                remoteCancellationSignal = unstableProvider.createCancellationSignal();
799                cancellationSignal.setRemote(remoteCancellationSignal);
800            }
801            try {
802                qCursor = unstableProvider.query(mPackageName, uri, projection,
803                        queryArgs, remoteCancellationSignal);
804            } catch (DeadObjectException e) {
805                // The remote process has died...  but we only hold an unstable
806                // reference though, so we might recover!!!  Let's try!!!!
807                // This is exciting!!1!!1!!!!1
808                unstableProviderDied(unstableProvider);
809                stableProvider = acquireProvider(uri);
810                if (stableProvider == null) {
811                    return null;
812                }
813                qCursor = stableProvider.query(
814                        mPackageName, uri, projection, queryArgs, remoteCancellationSignal);
815            }
816            if (qCursor == null) {
817                return null;
818            }
819
820            // Force query execution.  Might fail and throw a runtime exception here.
821            qCursor.getCount();
822            long durationMillis = SystemClock.uptimeMillis() - startTime;
823            maybeLogQueryToEventLog(durationMillis, uri, projection, queryArgs);
824
825            // Wrap the cursor object into CursorWrapperInner object.
826            final IContentProvider provider = (stableProvider != null) ? stableProvider
827                    : acquireProvider(uri);
828            final CursorWrapperInner wrapper = new CursorWrapperInner(qCursor, provider);
829            stableProvider = null;
830            qCursor = null;
831            return wrapper;
832        } catch (RemoteException e) {
833            // Arbitrary and not worth documenting, as Activity
834            // Manager will kill this process shortly anyway.
835            return null;
836        } finally {
837            if (qCursor != null) {
838                qCursor.close();
839            }
840            if (cancellationSignal != null) {
841                cancellationSignal.setRemote(null);
842            }
843            if (unstableProvider != null) {
844                releaseUnstableProvider(unstableProvider);
845            }
846            if (stableProvider != null) {
847                releaseProvider(stableProvider);
848            }
849        }
850    }

大概的意思就是先调用不稳定的提供器,如果获取内容失败,那么启动稳定的提供器,如果得到结果,执行wrap操作.那么我们继续跟踪稳定的提供器stableProvider.这里为Provider提供接口.那么Provider就应该有具体实现,由于这个是系统提供的组件,我们可以在Package包下找到MediaProvider.java.

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值