검색결과 리스트
글
Content 의 Uri 로부터 FilePath 가져오기
Android 개발을 하다보면, 폰의 스토리지에서 파일을 불러오는 기능을 구현할 때가 많습니다.
예를들면, 사진 편집을 위해서 앨범에서 파일을 불러온다든지, 파일 전송을 위해서 음악 파일을 가져온다든지 하는 기능들 말입니다.
짜증나는 Uri
보통 파일을 읽어올때, 아래와 같은 형식으로 Intent 를 사용합니다.
다음은 wav 파일을 선택하는 경우에 대한 코드입니다.
Intent intent_upload = new Intent();
intent_upload.setType("audio/x-wav");
intent_upload.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(intent_upload, 1);
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(requestCode == 1 && resultCode == RESULT_OK) {
Uri fileUri = data.getData();
}
}
이제 위의 fileUri 를 가지고 절대적인 filePath 를 뽑아내려면 어떻게 해야 할까요?
"/storage/emulated/0/xxx.wav" 요런 형태 말입니다.
fileUri.getPath() 를 하면, 운이 좋은 경우에는 한번에 가져와 지는 경우가 있습니다.
"/storage/" 형태 말입니다.
즉 이것은 호출되는(실행한) Intent 가 어떻게 주느냐에 달린것이라 할 수 있겠지요.
그런데, Android 6.0.1 에서는 거지같이 넘어옵니다.
악명높은 media id 가 넘어오죠.
아래처럼 말이죠.
"/document/audio:2898"
어쩌라고...............
개인적으로 이런 형태의 Uri 를 아무런 쓰잘데기가 없습니다.
(열받아서 하는 소리입니다. ㅎ)
아무튼 이런 놈들은 Media DB 에서 Query 를 통해, absolute path 를 뽑아내야 합니다.
아래 코드에 보면 MediaStore.Files ~ 로 시작하는 값들이 있는데,,
뽑아낸 것이 Image 이냐, Audio 이냐 Video 이냐에 따라서, 조금씩 바뀔 수 있습니다.
그런데 아마도 코드에서처럼 Files. 는 웬만해서 제대로 다 뽑아질 겁니다.
대략적인 형태는 아래와 같습니다.
private String getRealPathFromURI(Uri contentUri) {
if (contentUri.getPath().startsWith("/storage")) {
return contentUri.getPath();
}
String id = DocumentsContract.getDocumentId(contentUri).split(":")[1];
String[] columns = { MediaStore.Files.FileColumns.DATA };
String selection = MediaStore.Files.FileColumns._ID + " = " + id;
Cursor cursor = getContentResolver().query(MediaStore.Files.getContentUri("external"), columns, selection, null, null);
try {
int columnIndex = cursor.getColumnIndex(columns[0]);
if (cursor.moveToFirst()) {
return cursor.getString(columnIndex);
}
} finally {
cursor.close();
}
return null;
}
/**
* Get a file path from a Uri. This will get the the path for Storage Access
* Framework Documents, as well as the _data field for the MediaStore and
* other file-based ContentProviders.
*
* @param context The context.
* @param uri The Uri to query.
* @author paulburke
*/
public static String getPath(final Context context, final Uri uri) {
final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
// DocumentProvider
if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
// ExternalStorageProvider
if (isExternalStorageDocument(uri)) {
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
if ("primary".equalsIgnoreCase(type)) {
return Environment.getExternalStorageDirectory() + "/" + split[1];
}
// TODO handle non-primary volumes
}
// DownloadsProvider
else if (isDownloadsDocument(uri)) {
final String id = DocumentsContract.getDocumentId(uri);
final Uri contentUri = ContentUris.withAppendedId(
Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));
return getDataColumn(context, contentUri, null, null);
}
// MediaProvider
else if (isMediaDocument(uri)) {
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
Uri contentUri = null;
if ("image".equals(type)) {
contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
} else if ("video".equals(type)) {
contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
} else if ("audio".equals(type)) {
contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
}
final String selection = "_id=?";
final String[] selectionArgs = new String[] {
split[1]
};
return getDataColumn(context, contentUri, selection, selectionArgs);
}
}
// MediaStore (and general)
else if ("content".equalsIgnoreCase(uri.getScheme())) {
return getDataColumn(context, uri, null, null);
}
// File
else if ("file".equalsIgnoreCase(uri.getScheme())) {
return uri.getPath();
}
return null;
}
/**
* Get the value of the data column for this Uri. This is useful for
* MediaStore Uris, and other file-based ContentProviders.
*
* @param context The context.
* @param uri The Uri to query.
* @param selection (Optional) Filter used in the query.
* @param selectionArgs (Optional) Selection arguments used in the query.
* @return The value of the _data column, which is typically a file path.
*/
public static String getDataColumn(Context context, Uri uri, String selection,
String[] selectionArgs) {
Cursor cursor = null;
final String column = "_data";
final String[] projection = {
column
};
try {
cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs,
null);
if (cursor != null && cursor.moveToFirst()) {
final int column_index = cursor.getColumnIndexOrThrow(column);
return cursor.getString(column_index);
}
} finally {
if (cursor != null)
cursor.close();
}
return null;
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is ExternalStorageProvider.
*/
public static boolean isExternalStorageDocument(Uri uri) {
return "com.android.externalstorage.documents".equals(uri.getAuthority());
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is DownloadsProvider.
*/
public static boolean isDownloadsDocument(Uri uri) {
return "com.android.providers.downloads.documents".equals(uri.getAuthority());
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is MediaProvider.
*/
public static boolean isMediaDocument(Uri uri) {
return "com.android.providers.media.documents".equals(uri.getAuthority());
}
출처 : http://stackoverflow.com/a/27271131
'Android' 카테고리의 다른 글
정신건강에 좋은 파일 공유하기 (1) | 2019.01.04 |
---|---|
Android Studio 2.2 에서 NDK 빌드하기 (외부 so파일 추가) (3) | 2016.10.11 |
Multi Touch - Translate, Scale, Rotate (2) | 2016.01.19 |
RECENT COMMENT