Android4.4之后SD卡存储方案
来源:互联网 发布:微信公众号树洞源码 编辑:程序博客网 时间:2024/05/21 08:39
由于Android4.4之后,Android限制了第三方应用在SD卡中的公用目录的写权限,所以我们无法再公用目录创建文件夹,写入文件,但是读操作不受限制,(系统应用如文件管理器,或者root用户不除外)
第三方应用想要写入SD卡,有以下几种方案:
1,Context.getExternalFilesDir()
获取应用的专有目录如:/storage/sdcard1/Android/data/com.xxx.email
第三方应用有该目录的读写权限,但是该目录下的文件不会被MediaScanner检索到,并且在应用删除后,该目录同样会被删除。
2,Context.getExternalMediaDirs()
Android5.0新增,该目录为:
/storage/sdcard1/Android/media/com.xxx.email
该目录和Context.getExternalFilesDir()获取的目录的唯一区别就是该目录下的文件能够被媒体扫描到,进而在如 相册中浏览到,并且可以通过MediaStore被其他应用获取。 应用删除后该目录会被删除。
(在金立手机上出现过没有写权限的时候,然后拔插sd卡后,又有了写权限,不知道是金立手机不稳定还是本身这个API不稳定)
3,Storage Access Framework (SAF)
中文guide:http://developer.android.com/intl/zh-cn/guide/topics/providers/document-provider.html
这个存储访问框架是Android4.4引入的。其功能类似于ContentProvider和ContentResolver
文件提供者-通过DocumentsProvider提供文件访问服务(例如云存储应用,Google云硬盘)
客户端应用-则通过调用 ACTION_OPEN_DOCUMENT和/或 ACTION_CREATE_DOCUMENT Intent 。接收文件提供者返回的文件。
选取器-系统提供的通用UI,用来访问浏览提供者提供的文件
比如通过:
Intent intent =newIntent(Intent.ACTION_OPEN_DOCUMENT);
获取一个图片时,系统会提供一个下图形式的选择器,让用户从中选择文件。类似于ACTION_PICK 或ACTION_GET_CONTENT。
除了上面所说的,Android5.0之后还提供了ACTION_OPEN_DOCUMENT_TREE这种方式来访问目录,并可以新建,删除文件。
我认为这会是Android存储方向上的趋势,操作方法如下:
1.通过Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
startActivityForResult(intent, DOC_TREE_CODE);
打开一个文件选择器(系统提供)。如下图:
2.用户可以在sd目录下新建目录,然后选择该目录。
在选择后,onActivityResult返回的intent中返回该目录的uri:
content://com.android.externalstorage.documents/tree/00F3-1408%3Awps
然后可以通过
buildDocumentUriUsingTree:可以获取文件或者文件夹本身的信息。
buildChildDocumentsUriUsingTree:可以获取文件夹下的内容信息。
示例代码如下:
ContentResolver contentResolver = getActivity().getContentResolver(); Uri docUri = DocumentsContract.buildDocumentUriUsingTree(uri, DocumentsContract.getTreeDocumentId(uri)); Uri childrenUri = DocumentsContract.buildChildDocumentsUriUsingTree(uri, DocumentsContract.getTreeDocumentId(uri));//通过docUri可以查询该文档或者目录的 名称,类型,flags(是否可写等信息) Cursor docCursor = contentResolver.query(docUri, new String[]{ Document.COLUMN_DISPLAY_NAME, Document.COLUMN_MIME_TYPE}, null, null, null); try { while (docCursor.moveToNext()) { Log.d(TAG, "found doc =" + docCursor.getString(0) + ", mime=" + docCursor .getString(1)); mCurrentDirectoryUri = uri; mCurrentDirectoryTextView.setText(docCursor.getString(0)); mCreateDirectoryButton.setEnabled(true); } } finally { closeQuietly(docCursor); }//通过childrenUri可以查询目录下子文件或者子目录的信息 Cursor childCursor = contentResolver.query(childrenUri, new String[]{ Document.COLUMN_DISPLAY_NAME, Document.COLUMN_MIME_TYPE, Document.COLUMN_DOCUMENT_ID,Document.COLUMN_FLAGS}, null, null, null); try { List<DirectoryEntry> directoryEntries = new ArrayList<>(); while (childCursor.moveToNext()) { Log.d(TAG, "found child=" + childCursor.getString(0) + ", mime=" + childCursor .getString(1)); DirectoryEntry entry = new DirectoryEntry(); entry.fileName = childCursor.getString(0); entry.mimeType = childCursor.getString(1); entry.docId = childCursor.getString(2); entry.flag = childCursor.getInt(3); directoryEntries.add(entry); } mAdapter.setDirectoryEntries(directoryEntries); mAdapter.setTreeUri(uri); mAdapter.setActivity(getActivity()); mAdapter.notifyDataSetChanged(); } finally { closeQuietly(childCursor); }
3.新建文件
通过createDocument
如
Uri dirPic = DocumentsContract.createDocument(cr, dir, "image/png", "pic2.png");
可以在文件夹下创建目录或者文档。返回的依然是Uri
如果想对新建的文件进行写操作(比如邮件下载)只能通过如下方式:
os = contentResolver.openOutputStream(dirPic);
获取文件的输出流,然后写入内容
4.删除文件
文件的删除则是:
//注意这里的pic这个uri是DocumentUriDocumentsContract.deleteDocument(contentResolver, pic))
综上
方案1和2可以实现将附件保存在SD卡上
优点:不用改变现有的存储结构,只需将sd卡下的附件存储位置限定在
/storage/sdcard1/Android/data/com.xxx.email或者/storage/sdcard1/Android/media/com.xxx.email下折腾。并且/storage/sdcard1/Android/data/com.xxx.email目录可以覆盖android4.4以上的系统
缺点:目录选择受限,并且随着应用卸载,该目录会被删除。
方案3.
优点:可以在5.0以上很好的解决sd卡下文件夹新建,随便哪里都可以建.并且这种操作方式也是一种趋势。
缺点:
1,Android4.4 和4.4W这两个版本是个空挡。
2,由于整套API是新的,不涉及File操作,所以所有应用内涉及到新建文件,删除文件的地方,都要写2套操作,一套是File的操作,一套是Uri的操作。并需要对系统版本进行判断。
参考:
Android源码:
android5.1\development\samples\ApiDemos\src\com\example\android\apis\content\DocumentsSample.java
示例代码:https://github.com/googlesamples/android-DirectorySelection
文档:http://developer.android.com/intl/zh-cn/guide/topics/providers/document-provider.html
- Android4.4之后SD卡存储方案
- Android4.4之后的外置SD卡文件读写的解决方法
- Android4.4之后的外置SD卡文件读写的解决方法
- 关于android4.4外置sd卡读写
- android4.4上sd卡的读写权限
- Android4.4 SounderRecorder不能保存文件至SD卡
- android4.4上sd卡的读写权限
- android4.4上sd卡的读写权限
- android4.4外置SD卡无写入权限
- Android4.4中不能发送SD卡就绪广播
- Android4.4拒绝发送扫描SD卡的广播
- Android4.4+ 外置SD卡不能写入 获取外置SD卡路径解决方案
- Android sd相关笔记 - Android4.4上应用写sd卡问题
- Android sd相关笔记 - Android4.4上应用写sd卡问题
- Android4.0实现双sd卡
- android4.4.4访问sd卡问题
- android 双SD卡切换(SD SWAP) 方案,如何恢复“设置->存储->默认存储器”的用户选择功
- 双SD卡切换(SD SWAP) 方案,如何恢复“设置->存储->默认存储器”的用户选择功能
- Long.parse和Number
- JQuery:视频+实战总结
- win7 win10下80端口被System进程占用的解决方法
- [Leetcode]Longest Increasing Subsequence
- vs2008编译osip2 eXosip2
- Android4.4之后SD卡存储方案
- cf#Wunder Fund Round 2016 -B- Guess the Permutation-构造-乱搞
- 进制转换
- Linux下卸载keepalived
- java8 stream.map和stream.forEach
- Java模拟post实现图片上传
- Kinect for Windows中文网站
- eclipse搭建erlang开发环境
- cf#Wunder Fund Round 2016 -C - Constellation-计算几何-水题