Seleccione varias imágenes de la galería de Android

114

Entonces, básicamente, lo que estoy tratando de lograr es abrir Galleryen Android y dejar que el usuario seleccione multiple images. Ahora bien, esta pregunta se ha hecho con frecuencia, pero no estoy satisfecho con las respuestas. Principalmente porque encontré algo interesante en los documentos en mi IDE (vuelvo a esto más tarde) y, por lo tanto, no quiero usar un adaptador personalizado sino solo el estándar.

Ahora mi código para seleccionar una imagen es:

Intent intent = new Intent();
intent.setType("image/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(Intent.createChooser(intent,"Select Picture"), 1);

Ahora la gente de SO y otros sitios web le dirán que tiene 2 opciones:

1) No lo use ACTION_GET_CONTENTsino en su ACTION_SEND_MULTIPLElugar.
Este no funciona. Este es de acuerdo con los documentos para sendingarchivos y no, retrievingy eso es exactamente lo que hace. Cuando uso ACTION_SEND_MULTIPLE, se abre una ventana en mi dispositivo donde tengo que seleccionar una aplicación para enviar mis datos. Eso no es lo que quiero, así que me pregunto cómo la gente consiguió esto con esta solución. ¿Me pierdo algo?

2) Implementar un custom Gallery. Ahora bien, esta es mi última opción que consideraré porque, en mi humilde opinión, no es lo que estoy buscando porque tengo que diseñarlo yo mismo Y ¿por qué diablos no puedes seleccionar varias imágenes en la galería de vainilla?

Debe haber una opción para esto ... Ahora, lo interesante que encontré es esto:
Encontré esto en la descripción de los documentos ACTION_GET_CONTENT.

Si la persona que llama puede manejar varios elementos devueltos (el usuario realiza una selección múltiple), entonces puede especificar EXTRA_ALLOW_MULTIPLE para indicar esto.

Esto es muy interesante. Aquí lo están refiriendo al caso de uso en el que un usuario puede seleccionar varios elementos.

Más adelante dicen en los documentos:

Puede utilizar EXTRA_ALLOW_MULTIPLE para permitir que el usuario seleccione varios elementos.

Entonces esto es bastante obvio, ¿verdad? Esto es lo que necesito. Pero mi siguiente pregunta es: ¿Dónde puedo poner esto EXTRA_ALLOW_MULTIPLE? Lo triste es que no puedo encontrar esto en ninguna parte de la guía developers.android y tampoco está definido como una constante en la clase INTENT.

¿Alguien puede ayudarme con esto EXTRA_ALLOW_MULTIPLE?

Dion Segijn
fuente
1
La solución @KyleShank funcionó para mí. La configuración le EXTRA_ALLOW_MULTIPLEpermite seleccionar varios elementos. Obtenga los URI llamando getClipData()a la intención devuelta en onActivityResult. El único problema es que el widget de la galería no permitirá la selección múltiple. En ese caso, al hacer clic en cualquier imagen, finalizará la selección y podrá obtener el URI (de un solo elemento) llamando getDataa la intención devuelta
Tanweer Alam

Respuestas:

122

La opción EXTRA_ALLOW_MULTIPLE se establece en la intención a través del método Intent.putExtra ():

intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);

Su código anterior debería verse así:

Intent intent = new Intent();
intent.setType("image/*");
intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
intent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(Intent.createChooser(intent,"Select Picture"), 1);

Nota: la EXTRA_ALLOW_MULTIPLEopción solo está disponible en Android API 18 y versiones posteriores.

Kyle Shank
fuente
Lo sé, pero como menciono en mi respuesta: "Lo triste es que no puedo encontrar esto en ninguna parte de la guía de developers.android y tampoco está definido como una constante en la clase INTENT". Mi IDE no reconoce Intent.EXTRA_ALLOW_MULTIPLE. Tengo el nivel de API 18 instalado. Mi IDE dice: "EXTRA_ALLOW_MULTIPLE no se puede resolver o no es un campo"
Dion Segijn
intent.putExtra (Intent.EXTRA_ALLOW_MULTIPLE, verdadero); use emulador, no admite selección múltiple.
qinmiao
11
Está seleccionando la imagen múltiple. pero ¿cómo obtener la URL de la imagen del resultado de la actividad?
John
4
Esto inicia el selector de imágenes y me permite seleccionar varias imágenes, pero no sé cómo obtener las URL en onActivityResult.
Tom Kincaid
5
Puede obtener las URL en el resultado Intent.getClipData. Tiene la matriz de ClipData Item.
Tam Huynh
71

Defina estas variables en la clase:

int PICK_IMAGE_MULTIPLE = 1; 
String imageEncoded;    
List<String> imagesEncodedList;

Supongamos que al hacer clic en un botón debería abrir la galería para seleccionar imágenes

 Intent intent = new Intent();
 intent.setType("image/*");
 intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
 intent.setAction(Intent.ACTION_GET_CONTENT);
 startActivityForResult(Intent.createChooser(intent,"Select Picture"), PICK_IMAGE_MULTIPLE);

Entonces debe anular el método onActivityResult

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    try {
        // When an Image is picked
        if (requestCode == PICK_IMAGE_MULTIPLE && resultCode == RESULT_OK
                    && null != data) {
            // Get the Image from data

            String[] filePathColumn = { MediaStore.Images.Media.DATA };
            imagesEncodedList = new ArrayList<String>();
            if(data.getData()!=null){

                Uri mImageUri=data.getData();

                // Get the cursor
                Cursor cursor = getContentResolver().query(mImageUri,
                            filePathColumn, null, null, null);
                // Move to first row
                cursor.moveToFirst();

                int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
                imageEncoded  = cursor.getString(columnIndex);
                cursor.close();

            } else {
                if (data.getClipData() != null) {
                    ClipData mClipData = data.getClipData();
                    ArrayList<Uri> mArrayUri = new ArrayList<Uri>();
                    for (int i = 0; i < mClipData.getItemCount(); i++) {

                        ClipData.Item item = mClipData.getItemAt(i);
                        Uri uri = item.getUri();
                        mArrayUri.add(uri);
                        // Get the cursor
                        Cursor cursor = getContentResolver().query(uri, filePathColumn, null, null, null);
                        // Move to first row
                        cursor.moveToFirst();

                        int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
                        imageEncoded  = cursor.getString(columnIndex);
                        imagesEncodedList.add(imageEncoded);
                        cursor.close();

                    }
                    Log.v("LOG_TAG", "Selected Images" + mArrayUri.size());
                }
            }
        } else {
            Toast.makeText(this, "You haven't picked Image",
                        Toast.LENGTH_LONG).show();
        }
    } catch (Exception e) {
        Toast.makeText(this, "Something went wrong", Toast.LENGTH_LONG)
                    .show();
    }

    super.onActivityResult(requestCode, resultCode, data);
}

TENGA EN CUENTA QUE: la galería no le brinda la posibilidad de seleccionar múltiples imágenes, por lo que aquí abrimos el estudio de todas las imágenes para que pueda seleccionar múltiples imágenes de ellas. y no olvides agregar los permisos a tu manifiesto

MUY IMPORTANTE: getData (); para obtener una sola imagen y la he almacenado aquí en imageEncoded String si el usuario selecciona múltiples imágenes, entonces deben almacenarse en la lista

Entonces debes verificar cuál es nulo para usar el otro

Deseo que tengas un buen intento y a los demás

Laith Mihyar
fuente
Me salté "intent.setType (" image / * ");" y envía a los usuarios directamente a la foto en lugar de darle la oportunidad de ir a la galería que no permite la selección de varias fotos. No estoy seguro de si es por eso, mi getData () nunca devuelve un valor nulo, por lo que terminé usando getClipData exclusivamente para la selección de imágenes únicas y múltiples.
Johnny Wu
1
solo use la parte data.getClipData () es suficiente, no es necesario verificar data.getData ()
truongnm
&& null! = data ??
Odaym
8
Uri uri = content: //com.android.providers.media.documents/document/image%3A772 uri tiene datos pero cursor.getString me devuelve nulo imageEncoded = cursor.getString (columnIndex);
Muhammad Zubair Ashraf
2
Fue útil, pero tuve que complementar con estas funciones para getPath: stackoverflow.com/a/20559175/6141959
Geynen
30

Muchas de estas respuestas tienen similitudes pero a todas les falta la parte más importante onActivityResult, verifique si data.getClipDataes nula antes de verificardata.getData

El código para llamar al selector de archivos:

Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("image/*"); //allows any image file type. Change * to specific extension to limit it
//**The following line is the important one!
intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
startActivityForResult(Intent.createChooser(intent, "Select Picture"), SELECT_PICTURES); //SELECT_PICTURES is simply a global int used to check the calling intent in onActivityResult

El código para obtener todas las imágenes seleccionadas:

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if(requestCode == SELECT_PICTURES) {
        if(resultCode == Activity.RESULT_OK) {
            if(data.getClipData() != null) {
                int count = data.getClipData().getItemCount(); //evaluate the count before the for loop --- otherwise, the count is evaluated every loop.
                for(int i = 0; i < count; i++)  
                    Uri imageUri = data.getClipData().getItemAt(i).getUri();
                    //do something with the image (save it to some directory or whatever you need to do with it here) 
                }
            } else if(data.getData() != null) {
                String imagePath = data.getData().getPath();
                //do something with the image (save it to some directory or whatever you need to do with it here)
            }
        }
    }
}

Tenga en cuenta que el selector de Android tiene Fotos y Galería disponibles en algunos dispositivos. Fotos permite seleccionar varias imágenes. La galería permite solo uno a la vez.

Mira_Cole
fuente
¿Qué es getClipData ()? ¿No es suficiente data.getData?
adi
1
En algunos dispositivos Samsung, los resultados serán diferentes a los de los dispositivos que no son Samsung. Si el usuario selecciona varios archivos, getData()a veces NO será nulo, pero solo tendrá un Uri. Si desea controlar cuando un usuario selecciona varios archivos, verifique getClipData()antes getData(): si los datos del clip no son nulos, es posible que el usuario haya seleccionado varias imágenes. Manejar getClipData antes de getData pero manejar ambos casos es importante para admitir diferentes dispositivos y, al mismo tiempo, permitir múltiples Uris.
Mira_Cole
@Mira_Code ¿Cómo puedo configurar las imágenes seleccionadas para diferentes vistas de imagen?
Hasnain Ghias
20

Espero que esta respuesta no sea tarde. Debido a que el widget de la galería no admite la selección múltiple de forma predeterminada, puede personalizar la vista de cuadrícula que aceptó su intención de selección múltiple. La otra opción es ampliar la vista de la galería y agregar su propio código para permitir la selección múltiple.
Esta es la biblioteca simple que puede hacerlo: https://github.com/luminousman/MultipleImagePick

Actualización :
del comentario de @ ilsy, CustomGalleryActivity en el uso de esta biblioteca manageQuery, que está en desuso, por lo que debería cambiarse getContentResolver().query()y darle me cursor.close()gusta a esta respuesta

R4j
fuente
@ R4j Sí, y escribí sobre eso: la biblioteca no está lista para usarse en proyectos. Necesita muchas actualizaciones para empezar a usarlo. Y sobre su actualización: no lo use getContentResolver().query()en el hilo de la interfaz de usuario. Lea sobre cargadores y biblioteca de soporte.
mbelsky
.cacheOnDisc()también en desuso, así que .cacheOnDisc(true)
cámbielo por un parámetro
5

Inicializar instancia:

private String imagePath;
private List<String> imagePathList;

En onActivityResult tienes que escribir este bloque If-else 2. Uno para una sola imagen y otro para múltiples imágenes.

if (requestCode == GALLERY_CODE && resultCode == RESULT_OK  && data != null){

    imagePathList = new ArrayList<>();

    if(data.getClipData() != null){

        int count = data.getClipData().getItemCount();
        for (int i=0; i<count; i++){

            Uri imageUri = data.getClipData().getItemAt(i).getUri();
            getImageFilePath(imageUri);
        }
    }
    else if(data.getData() != null){

        Uri imgUri = data.getData();
        getImageFilePath(imgUri);
    }
}

La parte más importante, obtener la ruta de la imagen de uri :

public void getImageFilePath(Uri uri) {

    File file = new File(uri.getPath());
    String[] filePath = file.getPath().split(":");
    String image_id = filePath[filePath.length - 1];

    Cursor cursor = getContentResolver().query(android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI, null, MediaStore.Images.Media._ID + " = ? ", new String[]{image_id}, null);
    if (cursor!=null) {
        cursor.moveToFirst();
        imagePath = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA));
        imagePathList.add(imagePath);
        cursor.close();
    }
}

Espero que esto le pueda ayudar.

Hasib Akter
fuente
1

Obtuve nulo del Cursor. Luego encontró una solución para convertir el Urien Bitmapque funciona perfectamente.

Aquí está la solución que me funciona:

@Override
public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
{

    if (resultCode == Activity.RESULT_OK) {

        if (requestCode == YOUR_REQUEST_CODE) {

            if (data != null) {

                if (data.getData() != null) {

                    Uri contentURI = data.getData();
                    ex_one.setImageURI(contentURI);

                    Log.d(TAG, "onActivityResult: " + contentURI.toString());
                    try {

                        Bitmap bitmap = MediaStore.Images.Media.getBitmap(context.getContentResolver(), contentURI);

                    } catch (IOException e) {
                        e.printStackTrace();
                    }

                } else {

                    if (data.getClipData() != null) {
                        ClipData mClipData = data.getClipData();
                        ArrayList<Uri> mArrayUri = new ArrayList<Uri>();
                        for (int i = 0; i < mClipData.getItemCount(); i++) {

                            ClipData.Item item = mClipData.getItemAt(i);
                            Uri uri = item.getUri();
                            try {
                                Bitmap bitmap = MediaStore.Images.Media.getBitmap(context.getContentResolver(), uri);
                            } catch (IOException e) {
                                e.printStackTrace();
                            }

                        }
                    }

                }

            }

        }

    }

}
Sudarshan
fuente
0

Hola, el código siguiente funciona bien.

 Cursor imagecursor1 = managedQuery(
    MediaStore.Images.Media.EXTERNAL_CONTENT_URI, columns, null,
    null, orderBy + " DESC");

   this.imageUrls = new ArrayList<String>();
  imageUrls.size();

   for (int i = 0; i < imagecursor1.getCount(); i++) {
   imagecursor1.moveToPosition(i);
   int dataColumnIndex = imagecursor1
     .getColumnIndex(MediaStore.Images.Media.DATA);
   imageUrls.add(imagecursor1.getString(dataColumnIndex));
  }

   options = new DisplayImageOptions.Builder()
  .showStubImage(R.drawable.stub_image)
  .showImageForEmptyUri(R.drawable.image_for_empty_url)
  .cacheInMemory().cacheOnDisc().build();

   imageAdapter = new ImageAdapter(this, imageUrls);

   gridView = (GridView) findViewById(R.id.PhoneImageGrid);
  gridView.setAdapter(imageAdapter);

Quieres más aclaraciones. http://mylearnandroid.blogspot.in/2014/02/multiple-choose-custom-gallery.html

Ramesh Thangaraj
fuente
1
si funciona, está bien. Es bueno señalar el código obsoleto, pero siempre que lo use sin problemas, está bien usarlo. Es importante saber por qué está obsoleto, si se trata de problemas de seguridad, el código más nuevo es más eficiente, etc. Pero dado que las aplicaciones de Android son compatibles con versiones posteriores, el código obsoleto seguirá funcionando en el futuro.
JStephen
0

También tuve el mismo problema. También quería que los usuarios pudieran tomar fotos fácilmente mientras seleccionaban fotos de la galería. No pude encontrar una forma nativa de hacer esto, por lo que decidí hacer un proyecto de código abierto. Es muy parecido a MultipleImagePick, pero es una mejor forma de implementarlo.

https://github.com/giljulio/android-multiple-image-picker

private static final RESULT_CODE_PICKER_IMAGES = 9000;


Intent intent = new Intent(this, SmartImagePicker.class);
startActivityForResult(intent, RESULT_CODE_PICKER_IMAGES);


@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    switch (requestCode){
        case RESULT_CODE_PICKER_IMAGES:
            if(resultCode == Activity.RESULT_OK){
                Parcelable[] parcelableUris = data.getParcelableArrayExtra(ImagePickerActivity.TAG_IMAGE_URI);

                //Java doesn't allow array casting, this is a little hack
                Uri[] uris = new Uri[parcelableUris.length];
                System.arraycopy(parcelableUris, 0, uris, 0, parcelableUris.length);

                //Do something with the uris array
            }
            break;

        default:
            super.onActivityResult(requestCode, resultCode, data);
            break;
    }
}
Gil Julio
fuente
0

Prueba este IntentChooser . Solo agregue algunas líneas de código, yo hice el resto por usted.

private void startImageChooserActivity() {
    Intent intent = ImageChooserMaker.newChooser(MainActivity.this)
            .add(new ImageChooser(true))
            .create("Select Image");
    startActivityForResult(intent, REQUEST_IMAGE_CHOOSER);
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (requestCode == REQUEST_IMAGE_CHOOSER && resultCode == RESULT_OK) {
        List<Uri> imageUris = ImageChooserMaker.getPickMultipleImageResultUris(this, data);
    }
}

PD: como se mencionó en las respuestas anteriores, EXTRA_ALLOW_MULTIPLE solo está disponible para API> = 18. Y algunas aplicaciones de galería no hacen que esta función esté disponible (Google Photos y Documents ( com.android.documentsui) funcionan.

Tuan Chau
fuente
No me permite elegir varias imágenes a pesar de que se agregaronintent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
Scorpion