首页 > 解决方案 > Android 10 将文件写入公共 DCIM 目录,非弃用方法

问题描述

我们有一个 Android 应用程序,现场工作人员可以在其中拍摄照片,这些照片存储在他们的手机上,并通过网络 API 上传。如果上传失败,他们确实有重试机制,但有时他们需要求助于从手机中提取图像。为了将应用程序升级到 Android 10 版本而不弃用,我被迫将图像写入应用程序内部目录。问题是当他们升级他们的应用程序时,他们会从应用程序中丢失他们的照片。(我也将图像复制到备份目录,但这看起来有点笨拙)

我想将图像写入:/storage/emulated/0/DCIM/GoTrialImages

相反,他们将去:/storage/emulated/0/Android/data/au.come.aceware.ktr.ktr/files/DCIM/GoTrialImages/photoIntent(其中 photoIntent 是发生这种情况的活动)

这是我从在线文章中复制和调整的代码:

String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
        String fileName = "JPEG_" + timeStamp + ".jpg";
        File mediaStorageDir = new File(getExternalFilesDir(Environment.DIRECTORY_DCIM + File.separator +"GoTrialPhotos"), TAG);
        // Create the storage directory if it does not exist
        if (!mediaStorageDir.exists() && !mediaStorageDir.mkdirs()){
            Log.d(TAG, "failed to create directory");
        }

        // Return the file target for the photo based on filename
        File file = new File(mediaStorageDir.getPath() + File.separator + fileName);
        Uri bmpUri = FileProvider.getUriForFile(this, BuildConfig.APPLICATION_ID + ".provider", file);

这是清单中的文件提供程序条目:

        android:name="androidx.core.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>```

and here is @xml/provider_paths:


    ```<?xml version="1.0" encoding="utf-8"?>
    <paths xmlns:android="http://schemas.android.com/apk/res/android">
        <external-path name="external_files" path="."/>
    </paths>```


1) Is it possible to do what I am seeking to do ?
2) How do I do it without using deprecated code

Many thanks in advance
Tony

Following the suggestion to use media store I kept most of the code for creating the app internal file name 
(mainly because I wanted the randomised display name):

    private File createImageFileV2() throws IOException
    {
        // Create an image file name
        String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
        String imageFileName = "JPEG_" + timeStamp + "_";
        imageFileNameToUseAtWebServerEnd = strTrial + "_" + timeStamp + "_" + strUserId + ".jpg";
        File[] storageDir = getExternalMediaDirs();
        File image = File.createTempFile(
                imageFileName,  /* prefix */
                ".jpg",         /* suffix */
                storageDir[0]     /* directory */
        );

        return image;
    }

I then passed the file object in to the following code:

public Uri testgetPhotoFileUri2(File f)
    {
        Uri uri = null;
        String strDisplayName = f.getName();
        final ContentValues values = new ContentValues();
        values.put(MediaStore.MediaColumns.DISPLAY_NAME, strDisplayName);
        values.put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg");
        values.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DCIM );

        final ContentResolver resolver = thisContext.getContentResolver();

        try
        {
            final Uri contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
            uri = resolver.insert(contentUri, values);

            if (uri == null)
                throw new IOException("Failed to create new MediaStore record.");
            return uri;
        }
        catch (IOException e)
        {

            if (uri != null) {
                // Don't leave an orphan entry in the MediaStore
                resolver.delete(uri, null, null);
            }

        }

        return uri;
    }

I then used the resulting uri as my camera uri:

takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, cameraUri);

However, when the OnActivityResult calls HandleBigCameraPhoto and attempts to extract the bitmap using the CameraUri:

    private void handleBigCameraPhoto() {
        Bitmap bitmap = null;
        if (cameraUri != null)
        {

            if (Build.VERSION.SDK_INT >= 29) {
                ImageDecoder.Source source = ImageDecoder.createSource(getApplicationContext().getContentResolver(), cameraUri);
                try {
                    bitmap = ImageDecoder.decodeBitmap(source);
                } catch (IOException e) {
                    e.printStackTrace();
                }

It error traps to "no such file or directory"

Does this mean that I need to most of my work (image resizing, rotation, etc) using my app private file only and then as a last step insert the bitmap in to media store (and then delete the app private file so the user does not see the file name twice under gallery, recents)?

标签: androiddirectorypublicfileprovider

解决方案


您不会使用已弃用的功能:

File file = new File(getExternalFilesDir(null)
.getParentFile()
.getParentFile()
.getParentFile()
.getParentFile(), "DCIM");

;-)。


推荐阅读