予想される動作
「ダウンロード」内に保存されているファイルを選択すると、ファイル名とパスを取得できるはずです
実際の動作
「ダウンロード」内に保存されているファイルを選択すると、nullが返ります。
問題を再現する手順
これが私が実装したコードです
public static String getPath(final Context context, final Uri uri) {
String id = DocumentsContract.getDocumentId(uri);
if (!TextUtils.isEmpty(id)) {
if (id.startsWith("raw:")) {
return id.replaceFirst("raw:", "");
}
try {
final boolean isOreo = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O;
String stringContentURI;
Uri contentUri;
if(isOreo){
stringContentURI = "content://downloads/my_downloads";
}else{
stringContentURI = "content://downloads/public_downloads";
}
contentUri = ContentUris.withAppendedId(
Uri.parse(stringContentURI), Long.valueOf(id));
return getDataColumn(context, contentUri, null, null);
} catch (NumberFormatException e) {
return null;
}
}
}
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 index = cursor.getColumnIndexOrThrow(column);
return cursor.getString(index);
}
} finally {
if (cursor != null)
cursor.close();
}
return null;
}
ただし、Androidデバイス内の他のフォルダーからファイルを選択するときに機能します
お知らせ下さい。みんな、ありがとう :)
現時点では、パスを取得するための最良の方法は次のとおりです。
URIから物理ファイルをInputStreamとして取得すると、ContentResolver.openInputStream()
を使用すると、実際のパスを知らなくてもファイルの内容にアクセスできます。
String id = DocumentsContract.getDocumentId(uri);
InputStream inputStream = getContentResolver().openInputStream(uri);
次に、それを一時ファイルとしてキャッシュストレージに書き込みます
File file = new File(getCacheDir().getAbsolutePath()+"/"+id);
writeFile(inputStream, file);
String filePath = file.getAbsolutePath();
一時ファイルをキャッシュされたストレージに書き込む方法は次のとおりです
void writeFile(InputStream in, File file) {
OutputStream out = null;
try {
out = new FileOutputStream(file);
byte[] buf = new byte[1024];
int len;
while((len=in.read(buf))>0){
out.write(buf,0,len);
}
} catch (Exception e) {
e.printStackTrace();
}
finally {
try {
if ( out != null ) {
out.close();
}
in.close();
} catch ( IOException e ) {
e.printStackTrace();
}
}
}
それが最善の方法であるかどうかはわかりませんが、コードは正しく機能しています:D
これが、この要旨から見つけた別の解決策です。 FileUtils.Java
使い方は次のとおりです。
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
Uri uri = data.getData();
File originalFile = new File(FileUtils.getRealPath(this,uri));
}
これは私が思いついたものです(Android Pieでテストされており、SDカードを想定しています):
private String getParentDirectory(@NonNull Uri uri) {
String uriPath = uri.getPath();
String filePath = Environment.getExternalStorageDirectory().getAbsolutePath();
if(uriPath != null) {filePath = new File(filePath.concat("/" + uriPath.split(":")[1])).getParent();}
return filePath;
}
private String getAbsolutePath(@NonNull Uri uri) {
String uriPath = uri.getPath();
String filePath = Environment.getExternalStorageDirectory().getAbsolutePath();
if(uriPath != null) {filePath = filePath.concat("/" + uriPath.split(":")[1]);}
return filePath;
}