使用适用于 Android 7.1.1 的 FileProvider 使用相机拍照后,我无法将文件保存到图库

Posted

技术标签:

【中文标题】使用适用于 Android 7.1.1 的 FileProvider 使用相机拍照后,我无法将文件保存到图库【英文标题】:I can't save file to gallery after taking photo by camera by using the FileProvider for Android 7.1.1 【发布时间】:2018-05-03 13:12:12 【问题描述】:

我使用 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已经被成功访问了,但是不知道为什么我不能把它添加到gallery中。我也无法在 android VM 目录中找到图像文件。 这是调试日志:

https://i.stack.imgur.com/JN9uJ.png

我使用 chickendinner 作为我的 domian,keep 是我的应用程序的名称。

谢谢!

【问题讨论】:

看看this 对不起.. 我读过这个,但我没明白。我想我使用了与该帖子的答案相同的方法。 @Aswin P Ashok:这正是 galleryAddPic() 方法所做的 【参考方案1】:

在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))); with sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.fromFile(f)));【参考方案2】:

您的代码句柄

将新照片作为 jpg 文件写入文件系统 通过广播Intent.ACTION_MEDIA_SCANNER_SCAN_FILE将新照片添加到媒体数据库 创建一个FileProvider,允许其他应用通过content-uri content://com.temp.test/...访问私有//Android/data/com.temp.test/files/Pictures/...文件

我假设 media-db 扫描器没有通过文件 uri 读取您的应用程序私有数据目录 Android/data/com.temp.test/files/Pictures 的权限,因此无法将新照片添加到 media-db。

Whatsapp 和其他应用程序将他们接收/发送的照片存储在公共可读内部存储器(即 /sdcard/PICTURES/WhatsApp/ )中,媒体扫描仪可以通过Intent.ACTION_MEDIA_SCANNER_SCAN_FILE 的file-uri 读取它。

我不知道,如果媒体扫描仪可以处理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/...”条目插入媒体数据库。


使用public readable internal memory directories 应该可以在没有文件提供程序的情况下工作

【讨论】:

嗨 k3b,我认为扫描仪具有读取权限,因为我有 对于内容:-uris,我认为媒体扫描仪无法处理它,因为我在 Android 7.1.1 上工作,它高于 Android 7.0 @k3b Uri contentUri = Uri.parse("content://com.temp.test/myTestImage.jpg");此行不起作用,因为该应用无权访问私有 URI。

以上是关于使用适用于 Android 7.1.1 的 FileProvider 使用相机拍照后,我无法将文件保存到图库的主要内容,如果未能解决你的问题,请参考以下文章

还必须保留哪些android 7.0 sdk组件才能支持android 7.1.1

使用适用于 android 的字节播放声音

kivy:适用于 android + C++ 的 python

使用适用于 Android 的 CastCompanionLibrary 扫描设备

Nest JS CORS 错误 0 未知,适用于 Android 浏览器,但适用于 PC 浏览器

为啥使用 KML 数据检索适用于 Android 的 Google 路线不再有效? [复制]