URI, Android KitKat의 새로운 스토리지 액세스 프레임워크에서 실제 경로 얻기
Android 4.4(KitKat)에서 새로운 갤러리에 액세스하기 전에 저는 다음과 같은 방법으로 SD 카드의 실제 경로를 얻었습니다.
public String getPath(Uri uri) {
String[] projection = { MediaStore.Images.Media.DATA };
Cursor cursor = managedQuery(uri, projection, null, null, null);
startManagingCursor(cursor);
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
return cursor.getString(column_index);
}
이제, 의도.ACTION_GET_CONTENT가 다른 데이터를 반환합니다.
이전:
content://media/external/images/media/62
이제:
content://com.android.providers.media.documents/document/image:62
어떻게 하면 SD 카드의 실제 경로를 얻을 수 있습니까?
이렇게 하면 MediaProvider, DownloadsProvider 및 ExternalStorageProvider에서 파일 경로를 가져오는 동시에 언급한 비공식 ContentProvider 메서드로 돌아갑니다.
/**
* 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());
}
이것들은 제 오픈 소스 라이브러리인 FileChooser에서 가져온 것입니다.
참고: 이 답변은 문제의 일부를 해결합니다.완전한 해결책(라이브러리 형태)은 Paul Burke의 답변을 참조하십시오.
하여 URI를 얻을 수 .document id
그런 다음 질문을 합니다.MediaStore.Images.Media.EXTERNAL_CONTENT_URI
또는MediaStore.Images.Media.INTERNAL_CONTENT_URI
(SD 카드 상황에 따라 다름).
문서 ID를 가져오는 방법
// Will return "image:x*"
String wholeID = DocumentsContract.getDocumentId(uriThatYouCurrentlyHave);
// Split at colon, use second item in the array
String id = wholeID.split(":")[1];
String[] column = { MediaStore.Images.Media.DATA };
// where id is equal to
String sel = MediaStore.Images.Media._ID + "=?";
Cursor cursor = getContentResolver().
query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
column, sel, new String[]{ id }, null);
String filePath = "";
int columnIndex = cursor.getColumnIndex(column[0]);
if (cursor.moveToFirst()) {
filePath = cursor.getString(columnIndex);
}
cursor.close();
참조:이 솔루션을 가져온 게시물을 찾을 수 없습니다.저는 원래 포스터에 여기에 기여해 달라고 부탁하고 싶었습니다.오늘 밤에 좀 더 살펴볼게요.
아래 답변은 더 이상 존재하지 않는 페이지에 https://stackoverflow.com/users/3082682/cvizv 에 의해 작성되었습니다. 그가 질문에 대답할 충분한 담당자가 없기 때문에, 저는 그것을 게시합니다.저는 학점이 없습니다.
public String getImagePath(Uri uri){
Cursor cursor = getContentResolver().query(uri, null, null, null, null);
cursor.moveToFirst();
String document_id = cursor.getString(0);
document_id = document_id.substring(document_id.lastIndexOf(":")+1);
cursor.close();
cursor = getContentResolver().query(
android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
null, MediaStore.Images.Media._ID + " = ? ", new String[]{document_id}, null);
cursor.moveToFirst();
String path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA));
cursor.close();
return path;
}
편집: 코드에 흐름이 있습니다. 장치에 둘 이상의 외부 저장소(외부 sdcard, 외부 usb 등)가 있는 경우 코드 위에 있는 것은 기본 저장소에서 작동하지 않습니다.
킷캣에서 새로운 갤러리에 액세스하기 전에 나는 이 방법으로 sdcard에서 나의 실제 경로를 얻었습니다.
그것은 결코 믿을 수 없었습니다.다음과 같은 요건은 없습니다.Uri
당신이 돌아왔다는 것.ACTION_GET_CONTENT
또는ACTION_PICK
은 요을인합니다로 인덱싱되어야 합니다.MediaStore
또는 파일 시스템에 있는 파일을 나타내야 합니다.Uri
예를 들어 암호화된 파일이 즉시 해독되는 스트림을 나타낼 수 있습니다.
어떻게 하면 sdcard에서 실제 경로를 얻을 수 있습니까?
다에해파일있필없습다니요는에 하는 파일이 필요는 .Uri
.
네, 저는 정말로 길이 필요합니다.
그런 다음 스트림에서 자신의 임시 파일로 파일을 복사하고 사용합니다.더 좋은 것은 스트림을 직접 사용하고 임시 파일을 사용하지 않는 것입니다.
의도가 변경되었습니다.ACTION_GET_CONTENT for Intent.ACTION_PICK
그것은 당신의 상황에 도움이 되지 않을 것입니다.다음과 같은 요건은 없습니다.ACTION_PICK
는 " 한대반니다입"에 대한 입니다.Uri
어떻게든 마법으로 도출할 수 있는 파일 시스템에 파일이 있습니다.
저도 똑같은 문제를 겪었습니다.웹사이트에 업로드하기 위해서는 파일 이름이 필요합니다.
제가 PICK으로 마음을 바꾸면 효과가 있었습니다.이것은 Android 4.4용 AVD와 Android 2.1용 AVD에서 테스트되었습니다.
READ_EXTERNAL_STORAGE 권한 추가:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
의도 변경:
Intent i = new Intent(
Intent.ACTION_PICK,
android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI
);
startActivityForResult(i, 66453666);
/* OLD CODE
Intent intent = new Intent();
intent.setType("image/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(
Intent.createChooser( intent, "Select Image" ),
66453666
);
*/
실제 경로를 얻기 위해 코드를 변경할 필요가 없었습니다.
// Convert the image URI to the direct file system path of the image file
public String mf_szGetRealPathFromURI(final Context context, final Uri ac_Uri )
{
String result = "";
boolean isok = false;
Cursor cursor = null;
try {
String[] proj = { MediaStore.Images.Media.DATA };
cursor = context.getContentResolver().query(ac_Uri, proj, null, null, null);
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
result = cursor.getString(column_index);
isok = true;
} finally {
if (cursor != null) {
cursor.close();
}
}
return isok ? result : "";
}
이 답변은 당신의 다소 모호한 설명에 근거한 것입니다.합니다: 당이의도행취동거생라각다니합고했을을신로으적.Intent.ACTION_GET_CONTENT
그리고 이제 당신은content://com.android.providers.media.documents/document/image:62
이전의 미디어 제공자 URI 대신 뒤로 돌아갔죠?
4는 Android 4.4(KitKat)에서 Documents Activity를 열 때 .Intent.ACTION_GET_CONTENT
가 실행되어 이미지를 선택할 수 있는 그리드 보기(또는 목록 보기)로 이동합니다. 그러면 다음 URI가 호출 컨텍스트(예)로 반환됩니다.content://com.android.providers.media.documents/document/image:62
(이것은 새 문서 공급자에 대한 URI이며, 일반 문서 공급자 URI를 클라이언트에 제공하여 기본 데이터를 추상화합니다.)
수 .Intent.ACTION_GET_CONTENT
Documents Activity(문서 작업)의 드로어를 사용하면(왼쪽에서 오른쪽으로 끌면 선택할 수 있는 갤러리가 있는 드로어 UI가 표시됩니다).킷캣 전처럼.
DocumentsActivity 클래스에서 선택할 항목을 선택하고 URI 파일이 필요한 경우 다음(이것은 hacky! 경고) 쿼리(콘텐츠 해결기 포함)를 수행할 수 있습니다.content://com.android.providers.media.documents/document/image:62
URI를 선택하고 커서에서 _display_name 값을 읽습니다.이 이름은 다소 고유한 이름입니다(로컬 파일의 파일 이름만 해당). 미디어 공급자에게 선택할 때 이 이름을 사용하여 이 선택에 해당하는 올바른 행을 여기서 가져올 수도 있습니다.
문서 공급자에 액세스하는 권장 방법은 다음에서 찾을 수 있습니다(파일/비트맵을 읽을 입력 스트림 또는 파일 설명자 가져오기).
사용해 보십시오.
//KITKAT
i = new Intent(Intent.ACTION_PICK,android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(i, CHOOSE_IMAGE_REQUEST);
onActivityResult에서 다음을 사용합니다.
Uri selectedImageURI = data.getData();
input = c.getContentResolver().openInputStream(selectedImageURI);
BitmapFactory.decodeStream(input , null, opts);
여기 폴 버크의 답변의 업데이트된 버전이 있습니다.Android 4.4(KitKat) 이하 버전에는 DocumentsContract 클래스가 없습니다.
KitKat 아래 버전에서 작업하려면 다음 클래스를 만듭니다.
public class DocumentsContract {
private static final String DOCUMENT_URIS =
"com.android.providers.media.documents " +
"com.android.externalstorage.documents " +
"com.android.providers.downloads.documents " +
"com.android.providers.media.documents";
private static final String PATH_DOCUMENT = "document";
private static final String TAG = DocumentsContract.class.getSimpleName();
public static String getDocumentId(Uri documentUri) {
final List<String> paths = documentUri.getPathSegments();
if (paths.size() < 2) {
throw new IllegalArgumentException("Not a document: " + documentUri);
}
if (!PATH_DOCUMENT.equals(paths.get(0))) {
throw new IllegalArgumentException("Not a document: " + documentUri);
}
return paths.get(1);
}
public static boolean isDocumentUri(Uri uri) {
final List<String> paths = uri.getPathSegments();
Logger.v(TAG, "paths[" + paths + "]");
if (paths.size() < 2) {
return false;
}
if (!PATH_DOCUMENT.equals(paths.get(0))) {
return false;
}
return DOCUMENT_URIS.contains(uri.getAuthority());
}
}
Android 4.4(KitKat) 및 다른 모든 이전 버전에서도 원활하게 실행되도록 ActivityResult()의 갤러리 선택기 코드의 이전 버전에서 다음과 같은 변경/수정 작업을 수행해야 합니다.
Uri selectedImgFileUri = data.getData();
if (selectedImgFileUri == null ) {
// The user has not selected any photo
}
try {
InputStream input = mActivity.getContentResolver().openInputStream(selectedImgFileUri);
mSelectedPhotoBmp = BitmapFactory.decodeStream(input);
}
catch (Throwable tr) {
// Show message to try again
}
언급URL : https://stackoverflow.com/questions/20067508/get-real-path-from-uri-android-kitkat-new-storage-access-framework
'source' 카테고리의 다른 글
JavaScript에서 File 개체를 인스턴스화하는 방법은 무엇입니까? (0) | 2023.09.04 |
---|---|
ASP에서 JQuery를 사용하여 컨트롤러 작업을 호출하는 방법.NET MVC (0) | 2023.09.04 |
마우스가 테이블의 행 위에 이동할 때 커서를 손으로 변경 (0) | 2023.09.04 |
SQL에서 count(열)와 count(*)의 차이점은 무엇입니까? (0) | 2023.09.04 |
Angular 2의 하위 구성 요소에서 상위 구성 요소 속성 업데이트 (0) | 2023.09.04 |