如何在Android Pie中使用Intent.ACTION_OPEN_DOCUMENT

问题描述 投票:1回答:1

我正在使用Android Pie中的Retrofit进行个人资料照片更改功能。

所以我成功地将用相机拍摄的照片上传到服务器。但是我不知道如何将从图库中选择的照片传输到我的服务器。(我对Java Kotlin中的任何代码都满意。)

我稍后再上传视频。

我在Google上搜索了很多东西,但是很难获得我想要的信息。

在Google文档中做得很好,但我不知道该怎么做。https://developer.android.com/guide/topics/providers/document-provider

[Google文档显示了使用位图或输入流或其他方法的示例。

我需要位图或输入流才能使用翻新来上传照片吗?

我实际上需要一个有效的uri。

public void performFileSearch() {
        Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
        intent.addCategory(Intent.CATEGORY_OPENABLE);
        intent.setType("image/*");
        startActivityForResult(intent, PICTURES_DIR_ACCESS_REQUEST_CODE);
}


@Override
public void onActivityResult(int requestCode, int resultCode,Intent resultData) {
    if (requestCode == READ_REQUEST_CODE && resultCode ==Activity.RESULT_OK) {
        Uri uri = null;
        if (resultData != null) {
            uri = resultData.getData();
            Log.i(TAG, "Uri: " + uri.toString());
            showImage(uri);
        }
    }
}


public void Edit_Profile (String Image_Uri) {
    File file = new File(Image_Uri);
    RequestBody requestBody = RequestBody.create(file, MediaType.parse("image/*"));

    MultipartBody.Part body = MultipartBody.Part.createFormData("uploaded_file", Num+ID+".jpg", requestBody);
}

实际上,onActivityResult返回以下类型的uri。

content://com.android.providers.media.documents/document/image%3A191474

因此,当我尝试使用该uri将其发送到服务器时,出现FileNotFoundException错误。

java retrofit2 androidx android-9.0-pie android-10.0
1个回答
0
投票

这是Android-Q中引入的隐私限制。当应用程序以API 29为目标并且应用程序不再可以直接访问从getExternalStorageDirectory方法返回的路径时,不建议直接访问共享/外部存储设备。使用特定于应用程序的目录来读写文件。

默认情况下,将针对Android 10及更高版本的应用指定为scoped access into external storage或范围存储。此类应用可以在外部存储设备中查看以下类型的文件,而无需请求任何与存储相关的用户权限:

应用程序特定目录中的文件,可使用getExternalFilesDir()访问。应用程序从媒体存储创建的照片,视频和音频剪辑。

阅读文档Open files using storage access framework

根据上下文,您可以做的一件事就是CommonsWare建议使用InputStreamRequestBody。否则,请复制所选文件到应用程序沙箱文件夹IE(特定于应用程序)目录,然后在没有任何许可的情况下从那里访问文件。请仅查看以下在Android-Q及更高版本中可用的实现。

执行文件搜索

private void performFileSearch(String messageTitle) {
        Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
        intent.addCategory(Intent.CATEGORY_OPENABLE);
        intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);
        intent.setType("application/*");
        String[] mimeTypes = new String[]{"application/x-binary,application/octet-stream"};
        if (mimeTypes.length > 0) {
            intent.putExtra(Intent.EXTRA_MIME_TYPES, mimeTypes);
        }

        if (intent.resolveActivity(getPackageManager()) != null) {
            startActivityForResult(Intent.createChooser(intent, messageTitle), OPEN_DIRECTORY_REQUEST_CODE);
        } else {
            Log.d("Unable to resolve Intent.ACTION_OPEN_DOCUMENT {}");
        }
    }

onActivityResult返回

@Override
public void onActivityResult(int requestCode, int resultCode, final Intent resultData) {
        // The ACTION_OPEN_DOCUMENT intent was sent with the request code OPEN_DIRECTORY_REQUEST_CODE.
        // If the request code seen here doesn't match, it's the response to some other intent,
        // and the below code shouldn't run at all.
        if (requestCode == OPEN_DIRECTORY_REQUEST_CODE) {
            if (resultCode == Activity.RESULT_OK) {
                // The document selected by the user won't be returned in the intent.
                // Instead, a URI to that document will be contained in the return intent
                // provided to this method as a parameter.  Pull that uri using "resultData.getData()"
                if (resultData != null && resultData.getData() != null) {
                    new CopyFileToAppDirTask().execute(resultData.getData());
                } else {
                    Log.d("File uri not found {}");
                }
            } else {
                Log.d("User cancelled file browsing {}");
            }
        }
    }

文件写入应用特定路径

public static final String FILE_BROWSER_CACHE_DIR = "CertCache";

@SuppressLint("StaticFieldLeak")
private class CopyFileToAppDirTask extends AsyncTask<Uri, Void, String> {
    private ProgressDialog mProgressDialog;

    private CopyFileToAppDirTask() {
        mProgressDialog = new ProgressDialog(YourActivity.this);
    }

    @Override
    protected void onPreExecute() {
        super.onPreExecute();
        mProgressDialog.setMessage("Please Wait..");
        mProgressDialog.show();
    }

    protected String doInBackground(Uri... uris) {
        try {
            return writeFileContent(uris[0]);
        } catch (IOException e) {
            Log.d("Failed to copy file {}" + e.getMessage());
            return null;
        }
    }

    protected void onPostExecute(String cachedFilePath) {
        mProgressDialog.dismiss();
          if (cachedFilePath != null) {
                Log.d("Cached file path {}" + cachedFilePath);
            } else {
               Log.d("Writing failed {}");
         }

    }
}

private String writeFileContent(final Uri uri) throws IOException {
    InputStream selectedFileInputStream =
            getContentResolver().openInputStream(uri);
    if (selectedFileInputStream != null) {
        final File certCacheDir = new File(getExternalFilesDir(null), FILE_BROWSER_CACHE_DIR);
        boolean isCertCacheDirExists = certCacheDir.exists();
        if (!isCertCacheDirExists) {
            isCertCacheDirExists = certCacheDir.mkdirs();
        }
        if (isCertCacheDirExists) {
            String filePath = certCacheDir.getAbsolutePath() + "/" + getFileDisplayName(uri);
            OutputStream selectedFileOutPutStream = new FileOutputStream(filePath);
            byte[] buffer = new byte[1024];
            int length;
            while ((length = selectedFileInputStream.read(buffer)) > 0) {
                selectedFileOutPutStream.write(buffer, 0, length);
            }
            selectedFileOutPutStream.flush();
            selectedFileOutPutStream.close();
            return filePath;
        }
        selectedFileInputStream.close();
    }
    return null;
}

  // Returns file display name.
    @Nullable
    private String getFileDisplayName(final Uri uri) {
        String displayName = null;
        try (Cursor cursor = getContentResolver()
                .query(uri, null, null, null, null, null)) {
            if (cursor != null && cursor.moveToFirst()) {
                displayName = cursor.getString(
                        cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME));
                Log.i("Display Name {}" + displayName);

            }
        }

        return displayName;
    }
© www.soinside.com 2019 - 2024. All rights reserved.