简体   繁体   中英

I can't save file to gallery after taking photo by camera by using the FileProvider for Android 7.1.1

I build my app with FileProvider and I want to save the image after I take it. But I can't find the image in the gallery. I found these source codes from the Android Studio tutorial. I don't know what is the problem. I tried use debugger and I think the createFile() is correct. I also have my bitmap works. It can display the image I take but I can't add the image to the gallery.

I have this in my 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>

And in the file_paths.xml I have

<?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>

This is how I write the activity

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);
}

Please help! Thank you!

I use debugger to test the galleryaddpic() and the URI has been accessed sucessfully, but I don't know why I can't add it to the gallery. I can't find the image file in the android VM directory either. This is the debug log:

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

I'm using chickendinner as my domian, and keep is the name of my app.

Thank you!

Your code handles

  • write new photo as a jpg-file to the filesystem
  • add new photo to media-db via broadcst Intent.ACTION_MEDIA_SCANNER_SCAN_FILE
  • create a FileProvider that allow other apps to access private //Android/data/com.temp.test/files/Pictures/... files through a content-uri content://com.temp.test/...

I assume that the media-db scanner has no read-permission to your app-s private data directory Android/data/com.temp.test/files/Pictures via a file-uri and therefore cannot add the new photo to media-db.

Whatsapp and other apps store their received/send photo in public readable internal memory (ie /sdcard/PICTURES/WhatsApp/ ) where the media scanner can read it via file-uri via Intent.ACTION_MEDIA_SCANNER_SCAN_FILE .

I donot know, if the media scanner can handle content: -uris instead of file uri-s : You can try this:

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);
}

Please let us know if this works.

If this does not work you can try to manually insert a "content://com.temp.test/..." entry into media database.


using public readable internal memory directories should work without a fileprovider

Call this function in onActivityResult. It worked for me!

It is in fragment.In activity you can use "this" instead of "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();
        }
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM