Cómo guardar una imagen en Android Q utilizando MediaStore?

Omar Abdelhafiz:

Aquí hay un enlace al nuevo Android Q Scoped almacenamiento .

De acuerdo con esta Desarrolladores de Android Buenas Prácticas Blog , storing shared media files(que es mi caso) debe hacerse utilizando el MediaStore API.

Excavando en los documentos y no puedo encontrar una función relevante.

Aquí está mi juicio en Kotlin:

val bitmap = getImageBitmap() // I have a bitmap from a function or callback or whatever
val name = "example.png" // I have a name

val picturesDirectory = getExternalFilesDir(Environment.DIRECTORY_PICTURES)!!

// Make sure the directory "Android/data/com.mypackage.etc/files/Pictures" exists
if (!picturesDirectory.exists()) {
    picturesDirectory.mkdirs()
}

try {
    val out = FileOutputStream(File(picturesDirectory, name))
    bitmap.compress(Bitmap.CompressFormat.PNG, 100, out)

    out.flush()
    out.close()

} catch(e: Exception) {
    // handle the error
}

El resultado es que mi imagen se guarda aquí Android/data/com.mypackage.etc/files/Pictures/example.pngcomo se describe en el mejor blog Prácticas comoStoring app-internal files


Mi pregunta es:

Cómo guardar una imagen utilizando la API MediaStore?


Respuestas en Java son igualmente aceptables.

¡Gracias por adelantado!


EDITAR

Gracias a PerracoLabs

Que realmente ayudado!

Sin embargo, hay 3 puntos más.

Aquí está mi código:

val name = "Myimage"
val relativeLocation = Environment.DIRECTORY_PICTURES + File.pathSeparator + "AppName"

val contentValues  = ContentValues().apply {
    put(MediaStore.Images.ImageColumns.DISPLAY_NAME, name)
    put(MediaStore.MediaColumns.MIME_TYPE, "image/png")

    // without this part causes "Failed to create new MediaStore record" exception to be invoked (uri is null below)
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
        put(MediaStore.Images.ImageColumns.RELATIVE_PATH, relativeLocation)
    }
}

val contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
var stream: OutputStream? = null
var uri: Uri? = null

try {
    uri = contentResolver.insert(contentUri, contentValues)
    if (uri == null)
    {
        throw IOException("Failed to create new MediaStore record.")
    }

    stream = contentResolver.openOutputStream(uri)

    if (stream == null)
    {
        throw IOException("Failed to get output stream.")
    }

    if (!bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream))
    {
        throw IOException("Failed to save bitmap.")
    }


    Snackbar.make(mCoordinator, R.string.image_saved_success, Snackbar.LENGTH_INDEFINITE).setAction("Open") {
        val intent = Intent()
        intent.type = "image/*"
        intent.action = Intent.ACTION_VIEW
        intent.data = contentUri
        startActivity(Intent.createChooser(intent, "Select Gallery App"))
    }.show()

} catch(e: IOException) {
    if (uri != null)
    {
        contentResolver.delete(uri, null, null)
    }

    throw IOException(e)

}
finally {
    stream?.close()
}

1- La imagen guardada no obtiene su nombre correcto "Myimage.png"

He intentado utilizar "Myimage" y "Myimage.PNG" pero tampoco funcionó.

La imagen siempre se sale con un nombre formado por números como:

1563468625314.jpg

Lo cual nos lleva al segundo problema:

2- La imagen se guarda como jpga pesar de que comprimen el mapa de bits en el formato de png.

No es un gran problema. Sólo por curiosidad, por qué.

3- El bit relativeLocation produce una excepción en dispositivos menos de Android Q. Después de rodear con la "versión de Android Comprobar" if, las imágenes se guardan directamente en la raíz de la Picturescarpeta.

Otra Gracias.


EDIT 2

Cambiado a:

uri = contentResolver.insert(contentUri, contentValues)
if (uri == null)
{
    throw IOException("Failed to create new MediaStore record.")
}

val cursor = contentResolver.query(uri, null, null, null, null)
DatabaseUtils.dumpCursor(cursor)
cursor!!.close()

stream = contentResolver.openOutputStream(uri)

Estos son los registros

I/System.out: >>>>> Dumping cursor android.content.ContentResolver$CursorWrapperInner@76da9d1
I/System.out: 0 {
I/System.out:    _id=25417
I/System.out:    _data=/storage/emulated/0/Pictures/1563640732667.jpg
I/System.out:    _size=null
I/System.out:    _display_name=Myimage
I/System.out:    mime_type=image/png
I/System.out:    title=1563640732667
I/System.out:    date_added=1563640732
I/System.out:    is_hdr=null
I/System.out:    date_modified=null
I/System.out:    description=null
I/System.out:    picasa_id=null
I/System.out:    isprivate=null
I/System.out:    latitude=null
I/System.out:    longitude=null
I/System.out:    datetaken=null
I/System.out:    orientation=null
I/System.out:    mini_thumb_magic=null
I/System.out:    bucket_id=-1617409521
I/System.out:    bucket_display_name=Pictures
I/System.out:    width=null
I/System.out:    height=null
I/System.out:    is_hw_privacy=null
I/System.out:    hw_voice_offset=null
I/System.out:    is_hw_favorite=null
I/System.out:    hw_image_refocus=null
I/System.out:    album_sort_index=null
I/System.out:    bucket_display_name_alias=null
I/System.out:    is_hw_burst=0
I/System.out:    hw_rectify_offset=null
I/System.out:    special_file_type=0
I/System.out:    special_file_offset=null
I/System.out:    cam_perception=null
I/System.out:    cam_exif_flag=null
I/System.out: }
I/System.out: <<<<<

Me di cuenta de la titleque se coincida con el nombre así que traté de añadir:

put(MediaStore.Images.ImageColumns.TITLE, name)

Todavía no funcionaba y aquí están los nuevos registros:

I/System.out: >>>>> Dumping cursor android.content.ContentResolver$CursorWrapperInner@51021a5
I/System.out: 0 {
I/System.out:    _id=25418
I/System.out:    _data=/storage/emulated/0/Pictures/1563640934803.jpg
I/System.out:    _size=null
I/System.out:    _display_name=Myimage
I/System.out:    mime_type=image/png
I/System.out:    title=Myimage
I/System.out:    date_added=1563640934
I/System.out:    is_hdr=null
I/System.out:    date_modified=null
I/System.out:    description=null
I/System.out:    picasa_id=null
I/System.out:    isprivate=null
I/System.out:    latitude=null
I/System.out:    longitude=null
I/System.out:    datetaken=null
I/System.out:    orientation=null
I/System.out:    mini_thumb_magic=null
I/System.out:    bucket_id=-1617409521
I/System.out:    bucket_display_name=Pictures
I/System.out:    width=null
I/System.out:    height=null
I/System.out:    is_hw_privacy=null
I/System.out:    hw_voice_offset=null
I/System.out:    is_hw_favorite=null
I/System.out:    hw_image_refocus=null
I/System.out:    album_sort_index=null
I/System.out:    bucket_display_name_alias=null
I/System.out:    is_hw_burst=0
I/System.out:    hw_rectify_offset=null
I/System.out:    special_file_type=0
I/System.out:    special_file_offset=null
I/System.out:    cam_perception=null
I/System.out:    cam_exif_flag=null
I/System.out: }
I/System.out: <<<<<

Y no puedo cambiar date_addeda un nombre.

Y MediaStore.MediaColumns.DATAestá en desuso.

¡Gracias por adelantado!

PerracoLabs:

Pruebe el método siguiente. Q Android ya se encarga de crear las carpetas si no existen. El ejemplo está programado en forma fija a la salida en la carpeta Imágenes. Si necesita una subcarpeta a continuación, añadir el nombre de la subcarpeta como a continuación:

final String relativeLocation = Environment.DIRECTORY_PICTURES + File.separator + “YourSubforderName”;

Tengamos en cuenta que el formato de compresión debe estar relacionado con el parámetro de tipo MIME. Por ejemplo, con un formato de compresión JPEG que el tipo MIME sería "image / jpeg", y así sucesivamente.

private void saveBitmap(@NonNull final Context context, @NonNull final Bitmap bitmap,
                        @NonNull final Bitmap.CompressFormat format, @NonNull final String mimeType,
                        @NonNull final String displayName) throws IOException
{
    final String relativeLocation = Environment.DIRECTORY_PICTURES;

    final ContentValues  contentValues = new ContentValues();
    contentValues.put(MediaStore.MediaColumns.DISPLAY_NAME, displayName);
    contentValues.put(MediaStore.MediaColumns.MIME_TYPE, mimeType);
    contentValues.put(MediaStore.MediaColumns.RELATIVE_PATH, relativeLocation);

    final ContentResolver resolver = context.getContentResolver();

    OutputStream stream = null;
    Uri uri = null;

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

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

        stream = resolver.openOutputStream(uri);

        if (stream == null)
        {
            throw new IOException("Failed to get output stream.");
        }

        if (bitmap.compress(format, 95, stream) == false)
        {
            throw new IOException("Failed to save bitmap.");
        }
    }
    catch (IOException e)
    {
        if (uri != null)
        {
            // Don't leave an orphan entry in the MediaStore
            resolver.delete(uri, null, null);
        }

        throw e;
    }
    finally
    {
        if (stream != null)
        {
            stream.close();
        }
    }
}

Supongo que te gusta

Origin http://43.154.161.224:23101/article/api/json?id=225966&siteId=1
Recomendado
Clasificación