インテントACTION_GET_CONTENTを使用してstartActivityForResultを呼び出します。一部のアプリは、このURIでデータを返します:
content:// media / external / images / media / 18122
それが画像なのかビデオなのか、それともカスタムコンテンツなのかわかりません。ContentResolverを使用して、このURIから実際のファイル名またはコンテンツタイトルを取得するにはどうすればよいですか?
インテントACTION_GET_CONTENTを使用してstartActivityForResultを呼び出します。一部のアプリは、このURIでデータを返します:
content:// media / external / images / media / 18122
それが画像なのかビデオなのか、それともカスタムコンテンツなのかわかりません。ContentResolverを使用して、このURIから実際のファイル名またはコンテンツタイトルを取得するにはどうすればよいですか?
@Durairajの答えは、ファイルのパスを取得することに固有のものです。検索しているのがファイルの実際の名前である場合(コンテンツ解決を使用する必要があるため、その時点で多くのcontent:// URIを取得する可能性があります)、次のことを行う必要があります。
(Durairajの回答からコピーされて変更されたコード)
String[] projection = {MediaStore.MediaColumns.DISPLAY_NAME};
Cursor metaCursor = cr.query(uri, projection, null, null, null);
if (metaCursor != null) {
try {
if (metaCursor.moveToFirst()) {
fileName = metaCursor.getString(0);
}
} finally {
metaCursor.close();
}
}
ここで注意すべき主な点MediaStore.MediaColumns.DISPLAY_NAME
は、コンテンツの実際の名前を返すを使用していることです。MediaStore.MediaColumns.TITLE
違いがわからないので、試してみることもできます。
このコード、またはプロジェクションを変更することで他のフィールドからファイル名を取得できます
String[] projection = {MediaStore.MediaColumns.DATA};
ContentResolver cr = getApplicationContext().getContentResolver();
Cursor metaCursor = cr.query(uri, projection, null, null, null);
if (metaCursor != null) {
try {
if (metaCursor.moveToFirst()) {
path = metaCursor.getString(0);
}
} finally {
metaCursor.close();
}
}
return path;
ファイル名を取得するには、新しいDocumentFile形式を使用できます。
DocumentFile documentFile = DocumentFile.fromSingleUri(this, data.getdata());
String fileName = documentFile.getName();
同じ問題を抱えているKotlinを使用している人は、拡張メソッドを定義して、ファイル名とサイズ(バイト単位)を一挙に取得できます。フィールドを取得できない場合は、nullを返します。
fun Uri.contentSchemeNameAndSize(): Pair<String, Int>? {
return contentResolver.query(this, null, null, null, null)?.use { cursor ->
if (!cursor.moveToFirst()) return@use null
val name = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)
val size = cursor.getColumnIndex(OpenableColumns.SIZE)
cursor.getString(name) to cursor.getInt(size)
}
}
このようにそれを使用してください
val nameAndSize = yourUri.contentNameAndSize()
// once you've confirmed that is not null, you can then do
val (name, size) = nameAndSize
例外がスローされる可能性がありますが、私にとってはこれまでに発生したことはありません(URIが有効なURIである限りcontent://
)。
private static String getRealPathFromURI(Context context, Uri contentUri)
{
String[] proj = { MediaStore.Images.Media.DATA };
CursorLoader loader = new CursorLoader(context, contentUri, proj, null, null, null);
Cursor cursor = loader.loadInBackground();
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
String result = cursor.getString(column_index);
cursor.close();
return result;
}
ここに示されているすべての回答と、いくつかのAirgramがSDKで行ったことを読んだ後、私が到達したものは次のとおりです-私がGithubでオープンソースにしたユーティリティ:
https://github.com/mankum93/UriUtilsAndroid/tree/master/app/src/main/java/com/androiduriutils
呼び出すのと同じくらい簡単UriUtils.getDisplayNameSize()
です。コンテンツの名前とサイズの両方を提供します。
注: content://URIでのみ機能します
コードを垣間見ることができます:
/**
* References:
* - https://www.programcreek.com/java-api-examples/?code=MLNO/airgram/airgram-master/TMessagesProj/src/main/java/ir/hamzad/telegram/MediaController.java
* - https://stackoverflow.com/questions/5568874/how-to-extract-the-file-name-from-uri-returned-from-intent-action-get-content
*
* @author Manish@bit.ly/2HjxA0C
* Created on: 03-07-2020
*/
public final class UriUtils {
public static final int CONTENT_SIZE_INVALID = -1;
/**
* @param context context
* @param contentUri content Uri, i.e, of the scheme <code>content://</code>
* @return The Display name and size for content. In case of non-determination, display name
* would be null and content size would be {@link #CONTENT_SIZE_INVALID}
*/
@NonNull
public static DisplayNameAndSize getDisplayNameSize(@NonNull Context context, @NonNull Uri contentUri){
final String scheme = contentUri.getScheme();
if(scheme == null || !scheme.equals(ContentResolver.SCHEME_CONTENT)){
throw new RuntimeException("Only scheme content:// is accepted");
}
final DisplayNameAndSize displayNameAndSize = new DisplayNameAndSize();
displayNameAndSize.size = CONTENT_SIZE_INVALID;
String[] projection = new String[]{MediaStore.Images.Media.DATA, OpenableColumns.DISPLAY_NAME, OpenableColumns.SIZE};
Cursor cursor = context.getContentResolver().query(contentUri, projection, null, null, null);
try {
if (cursor != null && cursor.moveToFirst()) {
// Try extracting content size
int sizeIndex = cursor.getColumnIndex(OpenableColumns.SIZE);
if (sizeIndex != -1) {
displayNameAndSize.size = cursor.getLong(sizeIndex);
}
// Try extracting display name
String name = null;
// Strategy: The column name is NOT guaranteed to be indexed by DISPLAY_NAME
// so, we try two methods
int nameIndex = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
if (nameIndex != -1) {
name = cursor.getString(nameIndex);
}
if (nameIndex == -1 || name == null) {
nameIndex = cursor.getColumnIndex(MediaStore.Images.Media.DATA);
if (nameIndex != -1) {
name = cursor.getString(nameIndex);
}
}
displayNameAndSize.displayName = name;
}
}
finally {
if(cursor != null){
cursor.close();
}
}
// We tried querying the ContentResolver...didn't work out
// Try extracting the last path segment
if(displayNameAndSize.displayName == null){
displayNameAndSize.displayName = contentUri.getLastPathSegment();
}
return displayNameAndSize;
}
}
Durairajによって提案されたソリューションは、射影配列として次のものを使用できます。
String[] projection = { "_data" };