Android7.0以上如何实现Uri转路径
这篇文章给大家分享的是有关Android7.0以上如何实现Uri转路径的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。
Android是什么
Android是一种基于Linux内核的自由及开放源代码的操作系统,主要使用于移动设备,如智能手机和平板电脑,由美国Google公司和开放手机联盟领导及开发。
网络上看到过很多种Uri转路径的方法,可基本上都只适用于很少的Uri值,可能没有结果(例如,对于由MediaStore索引的非本地文件),也可能没有可用的结果(例如,对于可移动存储上的文件)。
解决方法
使用ContentResolver和openInputStream()在Uri标识的内容上获取InputStream。在控制的文件上使用InputStream和FileOutputStream复制内容,然后使用该文件。
代码如下:
privatestaticStringgetFilePathForN(Contextcontext,Uriuri){ try{ CursorreturnCursor=context.getContentResolver().query(uri,null,null,null,null); intnameIndex=returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME); returnCursor.moveToFirst(); Stringname=(returnCursor.getString(nameIndex)); Filefile=newFile(context.getFilesDir(),name); InputStreaminputStream=context.getContentResolver().openInputStream(uri); FileOutputStreamoutputStream=newFileOutputStream(file); intread=0; intmaxBufferSize=1*1024*1024; intbytesAvailable=inputStream.available(); intbufferSize=Math.min(bytesAvailable,maxBufferSize); finalbyte[]buffers=newbyte[bufferSize]; while((read=inputStream.read(buffers))!=-1){ outputStream.write(buffers,0,read); } returnCursor.close(); inputStream.close(); outputStream.close(); returnfile.getPath(); }catch(Exceptione){ e.printStackTrace(); } returnnull; }
附上全系统的代码:
/** *文件Uri转路径(兼容各品牌手机) */ publicclassPathUtils{ /** *android7.0以上处理方法 */ privatestaticStringgetFilePathForN(Contextcontext,Uriuri){ try{ CursorreturnCursor=context.getContentResolver().query(uri,null,null,null,null); intnameIndex=returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME); returnCursor.moveToFirst(); Stringname=(returnCursor.getString(nameIndex)); Filefile=newFile(context.getFilesDir(),name); InputStreaminputStream=context.getContentResolver().openInputStream(uri); FileOutputStreamoutputStream=newFileOutputStream(file); intread=0; intmaxBufferSize=1*1024*1024; intbytesAvailable=inputStream.available(); intbufferSize=Math.min(bytesAvailable,maxBufferSize); finalbyte[]buffers=newbyte[bufferSize]; while((read=inputStream.read(buffers))!=-1){ outputStream.write(buffers,0,read); } returnCursor.close(); inputStream.close(); outputStream.close(); returnfile.getPath(); }catch(Exceptione){ e.printStackTrace(); } returnnull; } /** *全平台处理方法 */ publicstaticStringgetPath(finalContextcontext,finalUriuri)throwsException{ finalbooleanisKitKat=Build.VERSION.SDK_INT>=Build.VERSION_CODES.KITKAT; finalbooleanisN=Build.VERSION.SDK_INT>=Build.VERSION_CODES.N; if(isN){ returngetFilePathForN(context,uri); } //DocumentProvider if(isKitKat&&DocumentsContract.isDocumentUri(context,uri)){ //ExternalStorageProvider if(isExternalStorageDocument(uri)){ finalStringdocId=DocumentsContract.getDocumentId(uri); finalString[]split=docId.split(":"); finalStringtype=split[0]; if("primary".equalsIgnoreCase(type)){ returnEnvironment.getExternalStorageDirectory()+"/"+split[1]; } } //DownloadsProvider elseif(isDownloadsDocument(uri)){ finalStringid=DocumentsContract.getDocumentId(uri); finalUricontentUri=ContentUris.withAppendedId( Uri.parse("content://downloads/public_downloads"),StringUtils.toLong(id)); returngetDataColumn(context,contentUri,null,null); } //MediaProvider elseif(isMediaDocument(uri)){ finalStringdocId=DocumentsContract.getDocumentId(uri); finalString[]split=docId.split(":"); finalStringtype=split[0]; UricontentUri=null; if("image".equals(type)){ contentUri=MediaStore.Images.Media.EXTERNAL_CONTENT_URI; }elseif("video".equals(type)){ contentUri=MediaStore.Video.Media.EXTERNAL_CONTENT_URI; }elseif("audio".equals(type)){ contentUri=MediaStore.Audio.Media.EXTERNAL_CONTENT_URI; } finalStringselection="_id=?"; finalString[]selectionArgs=newString[]{ split[1] }; returngetDataColumn(context,contentUri,selection,selectionArgs); } } //MediaStore(andgeneral) elseif("content".equalsIgnoreCase(uri.getScheme())){ returngetDataColumn(context,uri,null,null); } //File elseif("file".equalsIgnoreCase(uri.getScheme())){ returnuri.getPath(); } returnnull; } /** *获取此Uri的数据列的值。这对于MediaStoreuri和其他基于文件的内容提供程序非常有用。 */ publicstaticStringgetDataColumn(Contextcontext,Uriuri,Stringselection, String[]selectionArgs){ Cursorcursor=null; finalStringcolumn="_data"; finalString[]projection={ column }; try{ cursor=context.getContentResolver().query(uri,projection,selection,selectionArgs, null); if(cursor!=null&&cursor.moveToFirst()){ finalintcolumn_index=cursor.getColumnIndexOrThrow(column); returncursor.getString(column_index); } }catch(IllegalArgumentExceptione){ //donothing }finally{ if(cursor!=null) cursor.close(); } returnnull; } publicstaticbooleanisExternalStorageDocument(Uriuri){ return"com.android.externalstorage.documents".equals(uri.getAuthority()); } publicstaticbooleanisDownloadsDocument(Uriuri){ return"com.android.providers.downloads.documents".equals(uri.getAuthority()); } publicstaticbooleanisMediaDocument(Uriuri){ return"com.android.providers.media.documents".equals(uri.getAuthority()); } }
参考资料:https://stackoverflow.com/questions/42508383/illegalargumentexception-column-data-does-not-exist
另发现一篇,亲测,Android 4.4到Android 10可用,测试的系统有VIVO、OPPO、MIUI、EMUI...
解决的国内产商问题:华为的黄色图标管理器,他返回了4.4的标准的Uri了,不是4.4以上的标准的Uri,导致解析的时候,判断到版本 > 4.4,然后用了4.4以上的标准的解析,然后失败了,并非不回调。
直接可用的代码片段:
publicclassFileUtils{ privateContextcontext; publicFileUtils(Contextcontext){ this.context=context; } publicStringgetFilePathByUri(Uriuri){ //以file://开头的 if(ContentResolver.SCHEME_FILE.equals(uri.getScheme())){ returnuri.getPath(); } //以/storage开头的也直接返回 if(isOtherDocument(uri)){ returnuri.getPath(); } //版本兼容的获取! Stringpath=getFilePathByUri_BELOWAPI11(uri); if(path!=null){ LogUtils.d("getFilePathByUri_BELOWAPI11获取到的路径为:"+path); returnpath; } path=getFilePathByUri_API11to18(uri); if(path!=null){ LogUtils.d("getFilePathByUri_API11to18获取到的路径为:"+path); returnpath; } path=getFilePathByUri_API19(uri); LogUtils.d("getFilePathByUri_API19获取到的路径为:"+path); returnpath; } privateStringgetFilePathByUri_BELOWAPI11(Uriuri){ //以content://开头的,比如content://media/extenral/images/media/17766 if(ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())){ Stringpath=null; String[]projection=newString[]{MediaStore.Images.Media.DATA}; Cursorcursor=context.getContentResolver().query(uri,projection,null,null,null); if(cursor!=null){ if(cursor.moveToFirst()){ intcolumnIndex=cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA); if(columnIndex>-1){ path=cursor.getString(columnIndex); } } cursor.close(); } returnpath; } returnnull; } privateStringgetFilePathByUri_API11to18(UricontentUri){ String[]projection={MediaStore.Images.Media.DATA}; Stringresult=null; CursorLoadercursorLoader=newCursorLoader(context,contentUri,projection,null,null,null); Cursorcursor=cursorLoader.loadInBackground(); if(cursor!=null){ intcolumn_index=cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA); cursor.moveToFirst(); result=cursor.getString(column_index); cursor.close(); } returnresult; } privateStringgetFilePathByUri_API19(Uriuri){ //4.4及之后的是以content://开头的,比如content://com.android.providers.media.documents/document/image%3A235700 if(ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())&&Build.VERSION.SDK_INT>=Build.VERSION_CODES.KITKAT){ if(DocumentsContract.isDocumentUri(context,uri)){ if(isExternalStorageDocument(uri)){ //ExternalStorageProvider StringdocId=DocumentsContract.getDocumentId(uri); String[]split=docId.split(":"); Stringtype=split[0]; if("primary".equalsIgnoreCase(type)){ if(split.length>1){ returnEnvironment.getExternalStorageDirectory()+"/"+split[1]; }else{ returnEnvironment.getExternalStorageDirectory()+"/"; } //ThisisforcheckingSDCard } }elseif(isDownloadsDocument(uri)){ //下载内容提供者时应当判断下载管理器是否被禁用 intstateCode=context.getPackageManager().getApplicationEnabledSetting("com.android.providers.downloads"); if(stateCode!=0&&stateCode!=1){ returnnull; } Stringid=DocumentsContract.getDocumentId(uri); //如果出现这个RAW地址,我们则可以直接返回! if(id.startsWith("raw:")){ returnid.replaceFirst("raw:",""); } if(id.contains(":")){ String[]tmp=id.split(":"); if(tmp.length>1){ id=tmp[1]; } } UricontentUri=Uri.parse("content://downloads/public_downloads"); LogUtils.d("测试打印Uri:"+uri); try{ contentUri=ContentUris.withAppendedId(contentUri,Long.parseLong(id)); }catch(Exceptione){ e.printStackTrace(); } Stringpath=getDataColumn(contentUri,null,null); if(path!=null)returnpath; //兼容某些特殊情况下的文件管理器! StringfileName=getFileNameByUri(uri); if(fileName!=null){ path=Environment.getExternalStorageDirectory().toString()+"/Download/"+fileName; returnpath; } }elseif(isMediaDocument(uri)){ //MediaProvider StringdocId=DocumentsContract.getDocumentId(uri); String[]split=docId.split(":"); Stringtype=split[0]; UricontentUri=null; if("image".equals(type)){ contentUri=MediaStore.Images.Media.EXTERNAL_CONTENT_URI; }elseif("video".equals(type)){ contentUri=MediaStore.Video.Media.EXTERNAL_CONTENT_URI; }elseif("audio".equals(type)){ contentUri=MediaStore.Audio.Media.EXTERNAL_CONTENT_URI; } Stringselection="_id=?"; String[]selectionArgs=newString[]{split[1]}; returngetDataColumn(contentUri,selection,selectionArgs); } } } returnnull; } privateStringgetFileNameByUri(Uriuri){ StringrelativePath=getFileRelativePathByUri_API18(uri); if(relativePath==null)relativePath=""; finalString[]projection={ MediaStore.MediaColumns.DISPLAY_NAME }; try(Cursorcursor=context.getContentResolver().query(uri,projection,null,null,null)){ if(cursor!=null&&cursor.moveToFirst()){ intindex=cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DISPLAY_NAME); returnrelativePath+cursor.getString(index); } } returnnull; } privateStringgetFileRelativePathByUri_API18(Uriuri){ finalString[]projection; if(android.os.Build.VERSION.SDK_INT>=android.os.Build.VERSION_CODES.Q){ projection=newString[]{ MediaStore.MediaColumns.RELATIVE_PATH }; try(Cursorcursor=context.getContentResolver().query(uri,projection,null,null,null)){ if(cursor!=null&&cursor.moveToFirst()){ intindex=cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.RELATIVE_PATH); returncursor.getString(index); } } } returnnull; } privateStringgetDataColumn(Uriuri,Stringselection,String[]selectionArgs){ finalStringcolumn=MediaStore.Images.Media.DATA; finalString[]projection={column}; try(Cursorcursor=context.getContentResolver().query(uri,projection,selection,selectionArgs,null)){ if(cursor!=null&&cursor.moveToFirst()){ finalintcolumn_index=cursor.getColumnIndexOrThrow(column); returncursor.getString(column_index); } }catch(IllegalArgumentExceptioniae){ iae.printStackTrace(); } returnnull; } privatebooleanisExternalStorageDocument(Uriuri){ return"com.android.externalstorage.documents".equals(uri.getAuthority()); } privatebooleanisOtherDocument(Uriuri){ //以/storage开头的也直接返回 if(uri!=null&&uri.getPath()!=null){ Stringpath=uri.getPath(); if(path.startsWith("/storage")){ returntrue; } if(path.startsWith("/external_files")){ returntrue; } } returnfalse; } privatebooleanisDownloadsDocument(Uriuri){ return"com.android.providers.downloads.documents".equals(uri.getAuthority()); } privatebooleanisMediaDocument(Uriuri){ return"com.android.providers.media.documents".equals(uri.getAuthority()); } }
调用 getFilePathByUri(Uri uri) 即可获得最终的路径。
感谢各位的阅读!关于“Android7.0以上如何实现Uri转路径”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,让大家可以学到更多知识,如果觉得文章不错,可以把它分享出去让更多的人看到吧!
推荐阅读
-
怎么使用Android基准配置文件Baseline Profile方案提升启动速度
-
HTML5如何实现禁止android视频另存为
-
学java好还是学php好?
-
Android如何实现多点触控功能
-
android怎么实现多点触摸应用
-
Android怎么实现手势划定区域裁剪图片
-
android怎么实现简单的矩形裁剪框
-
Android单选多选按钮怎么使用
-
Android中如何利用oncreate获取控件高度或宽度
Android中如何利用oncreate获取控件高度或宽度本篇内容...
-
Android中怎么使用onSaveInstanceState()方法
Android中怎么使用onSaveInstanceState()方法...