使用Android 7.1.1的FileProvider拍照后无法将文件保存到相册。

3

我用FileProvider构建我的应用程序,并希望在拍摄后保存图像,但是我无法在相册中找到该图像。

我从Android Studio教程中找到了这些源代码。我不知道问题出在哪里。我尝试使用调试器,认为createFile()是正确的。我的位图也可以工作,它可以显示我拍摄的图像,但我无法将图像添加到相册中。

我在Manifest.xml中有以下内容

<provider
        android:name="android.support.v4.content.FileProvider"
        android:authorities="com.temp.test"
        android:exported="false"
        android:grantUriPermissions="true">
        <meta-data
            android:name="android.support.FILE_PROVIDER_PATHS"
            android:resource="@xml/file_paths"/>
</provider>

在 file_paths.xml 文件中,我有以下内容:
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
       <external-path name="external" path="Android/data/com.temp.test/files/Pictures" />
</paths>

这是我编写活动的方式。
private String mCurrentPhotoPath;
private ImageView mImageView;
private ImageButton StartCameraBtn;
private File photoFile = null;

//requestCode
private static final int REQUEST_IMAGE_CAPTURE = 1;

@Override
protected void onCreate(Bundle savedInstanceState)
{
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_photo_note);

    mImageView = (ImageView) findViewById(R.id.imageView);

    StartCameraBtn = (ImageButton) findViewById(R.id.StartCamera);

    StartCameraBtn.setOnClickListener(this);
}
public void onClick(View view)
{
    clearAllFocus();
    switch (view.getId())
    {
        case R.id.StartCamera:
            Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
            if (takePictureIntent.resolveActivity(getPackageManager()) != null)
            {
                try
                {
                    photoFile = createFile();
                }
                catch (IOException e)
                {
                    e.printStackTrace();
                }
                if(photoFile != null){
                    Uri photoURI = FileProvider.getUriForFile(this,
                            "com.temp.test",
                            photoFile);
                    takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);
                    startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE);
                }
            }
            break;
...
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
    mImageView.setImageBitmap(null);

    switch (requestCode)
    {
        case REQUEST_IMAGE_CAPTURE:
            if (resultCode == RESULT_OK)
            {
                setPic();
                galleryAddPic();
            }
            break;
    }
}
private File createFile() throws IOException
{
    // Create an image file name
    String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
    String imageFileName = "JPEG_" + timeStamp + "_";
    File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES);
    File image = File.createTempFile(
            imageFileName,  /* prefix */
            ".jpg",         /* suffix */
            storageDir      /* directory */
    );

    // Save a file: path for use with ACTION_VIEW intents
    mCurrentPhotoPath = image.getAbsolutePath();
    return image;
}

private void galleryAddPic()
{
    Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
    File f = new File(mCurrentPhotoPath);
    Uri contentUri = Uri.fromFile(f);
    mediaScanIntent.setData(contentUri);
    this.sendBroadcast(mediaScanIntent);
}
private void setPic()
{
    // Get the dimensions of the View
    int targetW = mImageView.getWidth();
    int targetH = mImageView.getHeight();

    // Get the dimensions of the bitmap
    BitmapFactory.Options bmOptions = new BitmapFactory.Options();
    bmOptions.inJustDecodeBounds = true;
    BitmapFactory.decodeFile(mCurrentPhotoPath, bmOptions);
    int photoW = bmOptions.outWidth;
    int photoH = bmOptions.outHeight;

    // Determine how much to scale down the image
    int scaleFactor = Math.min(photoW/targetW, photoH/targetH);

    // Decode the image file into a Bitmap sized to fill the View
    bmOptions.inJustDecodeBounds = false;
    bmOptions.inSampleSize = scaleFactor;
    bmOptions.inPurgeable = true;

    Bitmap bitmap = BitmapFactory.decodeFile(mCurrentPhotoPath, bmOptions);
    mImageView.setImageBitmap(bitmap);
}

请帮忙!谢谢!

我使用调试器测试了galleryaddpic(),URI已经成功访问,但是我不知道为什么无法将其添加到图库中。我在Android虚拟机目录中也找不到图像文件。

这是调试日志:

https://istack.dev59.com/JN9uJ.webp

我的域名是chickendinner,应用程序名称是keep。

谢谢!


请看此链接:https://stackoverflow.com/questions/19558188/photo-does-not-show-up-to-gallery - Aswin P Ashok
抱歉,我已经阅读过此内容,但是我并没有理解。我认为我使用的是与那篇帖子中展示的答案相同的方法。 - Kurou
@Aswin P Ashok:这正是方法galleryAddPic()的作用。 - k3b
2个回答

3

在 onActivityResult 中调用此函数。它对我有效!

它是在片段中的。在活动中,你可以使用“this”代替“getActivity()”。

private void galleryAddPic() {
        File f = new File(imageFilePath); //set your picture's path

        try {
            MediaStore.Images.Media.insertImage(getActivity().getContentResolver(),
                    f.getAbsolutePath(), f.getName(), null);
            getActivity().sendBroadcast(new Intent(
                    Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.fromFile(f)));
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }

将以下程序相关内容从英语翻译成中文。仅返回已翻译的文本:在Activity中,将getActivity()。sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE,Uri.fromFile(f)))替换为sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE,Uri.fromFile(f))); - Yakub

2

您的代码处理以下内容:

  • 将新照片以jpg文件格式写入文件系统
  • 通过广播Intent.ACTION_MEDIA_SCANNER_SCAN_FILE将新照片添加到媒体数据库中
  • 创建一个FileProvider,允许其他应用程序通过内容URIcontent://com.temp.test/...访问私有目录//Android/data/com.temp.test/files/Pictures/...中的文件

我认为媒体数据库扫描器没有读取您的应用程序私有数据目录Android/data/com.temp.test/files/Pictures的权限,因此无法通过文件URI将新照片添加到媒体数据库中。

WhatsApp和其他应用程序将其接收/发送的照片存储在可公开读取的内部存储器中(例如/sdcard/PICTURES/WhatsApp/),因此媒体扫描器可以通过文件URI通过Intent.ACTION_MEDIA_SCANNER_SCAN_FILE读取它们。

我不知道媒体扫描器是否可以处理content: -uris而不是file uri-s:您可以尝试这样做:

private void galleryAddPic()
{
    Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
    // assume that mCurrentPhotoPath ="Android/data/com.temp.test/files/Pictures/myTestImage.jpg"
    // can be accessed from outside as "content://com.temp.test/myTestImage.jpg"
    Uri contentUri = Uri.parse("content://com.temp.test/myTestImage.jpg");
    mediaScanIntent.setData(contentUri);
    this.sendBroadcast(mediaScanIntent);
}

请告诉我们这是否可行。
如果不行,您可以尝试手动将“content://com.temp.test/…”条目插入媒体数据库。
使用“公共可读内部存储目录”应该可以不用文件提供程序。

嗨k3b,我认为扫描仪具有读取权限,因为我有以下内容:<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="18"/> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> 对于内容:-uris,我认为媒体扫描程序无法处理它,因为我正在使用Android 7.1.1,这高于Android 7.0 @k3b - Kurou
Uri contentUri = Uri.parse("content://com.temp.test/myTestImage.jpg"); 这行代码无法工作,因为应用程序没有访问私有URI的权限。 - Kurou

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接