TL:DR; DocumentFile を使用してフォルダーとサブフォルダーを作成する方法と、このクラスを使用して作成したファイルを削除する方法を説明しました。onActivityResult() と documentFile.getUri.toString() から返される URI は同じではありません。私の質問は、SAF UI を使用せずに有効な Uri を取得して、可能であればハックを使用せずにフォルダーとファイルを操作する方法です。
これまでに学んだことを共有し、質問をさせてください。フォルダーの URI を取得して操作する場合は、 with を使用Intent
しACTION_OPEN_DOCUMENT_TREE
てフォルダーにアクセスするための URI を取得し、その uri に W/R パーミッションを設定する必要があります。
onActivityResult に付与された永続的なアクセス許可:
final int takeFlags = data.getFlags() & (Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
// Check for the freshest data.
getContentResolver().takePersistableUriPermission(treeUri, takeFlags);
デバイスのメイン フォルダを選択した場合:
Uri treeUri = data.getData();
treeUri.toString()
戻り値: content://com.android.externalstorage.documents/tree/primary:
File mediaStorageDir = new File(Environment.getExternalStorageDirectory(), "");
戻り値: storage/emulated/0
new File(treeUri.toString()).getAbsolutePath();
戻り値: content:/com.android.externalstorage.documents/tree/primary:
メインフォルダーのパスを取得するために DocumentFile クラスを使用すると、取得する
DocumentFile saveDir = null;
saveDir = DocumentFile.fromFile(Environment.getExternalStorageDirectory());
String uriString = saveDir.getUri().toString();
戻り値: file:///storage/emulated/0
私の最初の質問は、DocumentFile クラスを使用してコンテンツを含む Uri を取得する方法です。
私は写真アプリを構築しています。デフォルトとして、DocumentFile クラスを使用して画像の初期フォルダーを設定したいと考えています。
@TargetApi(19)
protected DocumentFile getSaveDirMainMemory() {
DocumentFile saveDir = null;
saveDir = DocumentFile.fromFile(Environment.getExternalStorageDirectory());
// saveDir =
// DocumentFile.fromFile(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM));
// saveDir =
// DocumentFile.fromFile(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES));
DocumentFile newDir = null;
/*
* Check or create Main Folder
*/
// Check if main folder exist
newDir = saveDir.findFile(DIR_MAIN);
// Folder does not exist, create it
if (newDir == null || !newDir.exists()) {
newDir = saveDir.createDirectory(DIR_MAIN);
}
/*
* Check or create Sub-Folder
*/
DocumentFile newSubDir = null;
// Check if sub-folder exist
newSubDir = newDir.findFile(DIR_SUB);
// Folder does not exist, create it
if (newSubDir == null || !newSubDir.exists()) {
newSubDir = newDir.createDirectory(DIR_SUB);
}
if (newSubDir != null && newSubDir.exists()) {
return newSubDir;
} else if (newDir != null && newDir.exists()) {
return newDir;
} else {
return saveDir;
}
}
このメソッドは、デバイスのメイン メモリ内に DIR_MAIN/DIR_SUB を作成するか、選択に応じて PICTURES または DCIM フォルダーを作成します。このデフォルトのフォルダーを使用して、この作成されたサブフォルダーに画像を保存します。newSubDir.getUri().toString(): file:///storage/emulated/0/MainFolder/SubFolderを取得します DIR_MAIN MainFolder、DIR_SUB: SubFolder という名前を付けてテストしました。
画像にアクセスまたは削除するには、このパスと作成した画像名を使用します
DocumentFile imageToDeletePath = DocumentFile.fromFile(new File(lastSavedImagePath));
DocumentFile imageToDelete = imageToDeletePath.findFile(lastSavedImageName);
Uri の形式が正しくないため、imageDelete は null を返します。
SAF ui を開いて UI onActivityResult を取得し、それを文字列として保存する場合、このメソッドを使用してディレクトリを取得し、Uri のアクセス許可を確認します。
@TargetApi(19)
protected DocumentFile getSaveDirNew(String uriString) {
DocumentFile saveDir = null;
boolean canWrite = isUriWritePermission(uriString);
if (canWrite) {
try {
saveDir = DocumentFile.fromTreeUri(MainActivity.this, Uri.parse(uriString));
} catch (Exception e) {
saveDir = null;
}
}
return saveDir;
}
文字列の Uri に書き込み権限があるかどうかを確認します。永続的な権限を取得または削除しないと、書き込み権限がない可能性があります。
private boolean isUriWritePermission(String uriString) {
boolean canWrite = false;
List<UriPermission> perms = getContentResolver().getPersistedUriPermissions();
for (UriPermission p : perms) {
if (p.getUri().toString().equals(uriString) && p.isWritePermission()) {
Toast.makeText(this, "canWrite() can write URI:: " + p.getUri().toString(), Toast.LENGTH_LONG).show();
canWrite = true;
break;
}
}
return canWrite;
}
有効なURIで画像を保存して使用した後
DocumentFile imageToDeletePath = DocumentFile.fromTreeUri(this, Uri.parse(lastSavedImagePath));
DocumentFile imageToDelete = imageToDeletePath.findFile(lastSavedImageName);