SDカードに存在するファイルを選択したい内部ストレージにないサーバーをアップロードしますが、サイズを取得するためのパスを取得できません。以下のコードを使用してファイルを選択する意図を開始しました。
_ intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("*/*");
String[] mimetypes = {"application/*"};
intent.putExtra(Intent.EXTRA_MIME_TYPES, mimetypes);
startActivityForResult(
Intent.createChooser(intent, "Select a File to Upload"), FILE_SELECT_CODE);
_
私が使用しているファイルへのパスを取得するために この回答 そしてユーザーがsdcard(リムーバブル)からファイルを選択しない限りそれは機能します。コードをデバッグして、typeがprimaryでないことがわかった場合、この条件の範囲内にはなりません。
_if("primary".equalsIgnoreCase(type)){
return Environment.getExternalStorageDirectory() + "/" + split[1];
}
_
それで、私の質問は、他に何があるのかということです。つまり、型がプライマリでない場合はどうなりますか?その場合、どのようにファイルへのパスを取得できますか?私は多くの質問とチュートリアルを検索しましたが、それらのいずれにも他にはありません。 この回答 のelse部分も試しましたが、System.getenv()
return null for "SECONDARY_STORAGE" and-のため、機能しません。 sdcard for "EXTERNAL_STORAGE"。試してみると、ファイルが見つからないという例外が発生します。
_if ("primary".equalsIgnoreCase(type)) {
return Environment.getExternalStorageDirectory() + "/" + split[1];
}else{
return System.getenv("EXTERNAL_STORAGE") + "/" + split[1];
}
_
ファイルのURIとドキュメントIDは次のようになります。
ri:content://com.Android.externalstorage.documents/document/0EF9-3110%3Adevice-2016-12-02-130553.png
docId:0EF9-3110:device-2016-12-02-130553.png
何か助けは??
Android Device Managerに時間を費やした後、解決策を見つけました。次のとおりです。
ドキュメントタイプIDがプライマリでない場合は、次を使用してパスを作成します。
filePath = "/storage/" + type + "/" + split[1];
EDIT: DocumentUriの場合、ファイルタイプに基づいてcontentUriを選択します
これが完全な機能です:
public static String getRealPathFromURI_API19(Context context, Uri uri) {
String filePath = "";
// 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];
} else {
if (Build.VERSION.SDK_INT > 20) {
//getExternalMediaDirs() added in API 21
File extenal[] = context.getExternalMediaDirs();
if (extenal.length > 1) {
filePath = extenal[1].getAbsolutePath();
filePath = filePath.substring(0, filePath.indexOf("Android")) + split[1];
}
}else{
filePath = "/storage/" + type + "/" + split[1];
}
return filePath;
}
} else if (isDownloadsDocument(uri)) {
// DownloadsProvider
final String id = DocumentsContract.getDocumentId(uri);
//final Uri contentUri = ContentUris.withAppendedId(
// Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));
Cursor cursor = null;
final String column = "_data";
final String[] projection = {column};
try {
cursor = context.getContentResolver().query(uri, projection, null, null, null);
if (cursor != null && cursor.moveToFirst()) {
final int index = cursor.getColumnIndexOrThrow(column);
String result = cursor.getString(index);
cursor.close();
return result;
}
} finally {
if (cursor != null)
cursor.close();
}
} else if (DocumentsContract.isDocumentUri(context, uri)) {
// MediaProvider
String wholeID = DocumentsContract.getDocumentId(uri);
// Split at colon, use second item in the array
String[] ids = wholeID.split(":");
String id;
String type;
if (ids.length > 1) {
id = ids[1];
type = ids[0];
} else {
id = ids[0];
type = ids[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[]{id};
final String column = "_data";
final String[] projection = {column};
Cursor cursor = context.getContentResolver().query(contentUri,
projection, selection, selectionArgs, null);
if (cursor != null) {
int columnIndex = cursor.getColumnIndex(column);
if (cursor.moveToFirst()) {
filePath = cursor.getString(columnIndex);
}
cursor.close();
}
return filePath;
} else {
String[] proj = {MediaStore.Audio.Media.DATA};
Cursor cursor = context.getContentResolver().query(uri, proj, null, null, null);
if (cursor != null) {
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DATA);
if (cursor.moveToFirst())
filePath = cursor.getString(column_index);
cursor.close();
}
return filePath;
}
return null;
}
アップロードコードを変更します。どこかにあります
FileInputStream fis = new FileInputStream(path);
への変更
InputStream is = getContentResolver().openInputStream(uri);
したがって、URIを直接使用してください。ファイルパスは必要ありません。
アプリケーションにFileProviderを実装するのは非常に簡単です。まず、AndroidManifest.xmlの次のようなタグの下にFileProviderタグを追加する必要があります:AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:Android="http://schemas.Android.com/apk/res/Android"
...
<application
...
<provider
Android:name="Android.support.v4.content.FileProvider"
Android:authorities="${applicationId}.provider"
Android:exported="false"
Android:grantUriPermissions="true">
<meta-data
Android:name="Android.support.FILE_PROVIDER_PATHS"
Android:resource="@xml/provider_paths"/>
</provider>
</application>
</manifest>
次に、resフォルダーの下のxmlフォルダーにprovider_paths.xmlファイルを作成します。フォルダーが存在しない場合は、作成する必要がある場合があります。
res/xml/provider_paths.xml
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:Android="http://schemas.Android.com/apk/res/Android">
<external-path name="external_files" path="."/>
</paths>
完了!これでFileProviderが宣言され、使用できるようになりました。
最後のステップは、MainActivity.Javaで以下のコード行を変更することです。
Uri photoURI = Uri.fromFile(createImageFile());
to
Uri photoURI = FileProvider.getUriForFile(MainActivity.this,
BuildConfig.APPLICATION_ID + ".provider",
createImageFile());
そして....完了!これで、アプリケーションは、AndroidNougat。Yah!を含むすべてのAndroidバージョンで完全に正常に動作するはずです。