Selecione várias imagens da galeria do Android

114

Então, basicamente o que estou tentando alcançar é abrir o Galleryno Android e deixar o usuário selecionar multiple images. Agora, esta pergunta tem sido feita com frequência, mas não estou satisfeito com as respostas. Principalmente porque encontrei algo interessante nos de docs em meu IDE (volto sobre isso mais tarde) e, portanto, não quero usar um adaptador personalizado, mas apenas o vanilla.

Agora, meu código para selecionar uma imagem é:

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

Agora, as pessoas no SO e em outros sites dirão que você tem 2 opções:

1) Não use, ACTION_GET_CONTENTmas ACTION_SEND_MULTIPLEsim.
Este não funciona. Este está de acordo com a documentação para sendingarquivos e não retrievinge é exatamente o que faz. Ao usar o ACTION_SEND_MULTIPLE, abri uma janela no meu dispositivo onde devo selecionar um aplicativo para enviar meus dados. Não é isso que eu quero, então me pergunto como as pessoas conseguiram isso com essa solução. Eu sinto falta de alguma coisa?

2) Implementar um custom Gallery. Agora, esta é a minha última opção que vou considerar porque imho não é o que estou procurando porque tenho que estilizá-lo sozinho E por que diabos você simplesmente não pode selecionar várias imagens na galeria vanilla?

Deve haver uma opção para isso .. Agora o que é interessante o que eu encontrei é o seguinte:
Eu achei isso na descrição da documentação do ACTION_GET_CONTENT.

Se o chamador puder lidar com vários itens retornados (o usuário executando várias seleções), ele pode especificar EXTRA_ALLOW_MULTIPLE para indicar isso.

Isso é muito interessante. Aqui, eles se referem ao caso de uso em que um usuário pode selecionar vários itens?

Mais tarde, eles dizem na documentação:

Você pode usar EXTRA_ALLOW_MULTIPLE para permitir que o usuário selecione vários itens.

Então, isso é bastante óbvio, certo? Isto é o que eu preciso. Mas minha seguinte pergunta é: Onde posso colocar isso EXTRA_ALLOW_MULTIPLE? O triste é que não consigo encontrar isso em nenhum lugar no guia developers.android e também não é definido como uma constante na classe INTENT.

Alguém pode me ajudar com isso EXTRA_ALLOW_MULTIPLE?

Dion Segijn
fonte
1
A solução @KyleShank funcionou para mim. A configuração EXTRA_ALLOW_MULTIPLEpermite que você selecione vários itens. Obtenha os URIs chamando o getClipData()intent retornado em onActivityResult. O único problema é que o widget da galeria não permite a seleção múltipla. Nesse caso, clicar em qualquer imagem encerrará a seleção e você poderá obter o URI (do item único) chamando getDatana intenção retornada
Tanweer Alam

Respostas:

122

A opção EXTRA_ALLOW_MULTIPLE é definida no intent por meio do método Intent.putExtra ():

intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);

Seu código acima deve ser semelhante a este:

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: a EXTRA_ALLOW_MULTIPLEopção está disponível apenas no Android API 18 e superior.

Kyle Shank
fonte
Eu sei disso, mas como mencionei na minha resposta: "O triste é que não consigo encontrar isso em nenhum lugar no guia developers.android e também não é definido como uma constante na classe INTENT." Meu IDE não reconhece Intent.EXTRA_ALLOW_MULTIPLE. Tenho a API de nível 18 instalada. Meu IDE diz: "EXTRA_ALLOW_MULTIPLE não pode ser resolvido ou não é um campo"
Dion Segijn
intent.putExtra (Intent.EXTRA_ALLOW_MULTIPLE, true); usar emulador, não suporta seleção múltipla.
qinmiao
11
Está selecionando a imagem múltipla. mas como obter o url da imagem no resultado da atividade ????
João,
4
Isso inicia o seletor de imagens e me permite selecionar várias imagens, mas não sei como obter os urls em onActivityResult.
Tom Kincaid de
5
Você pode obter os urls no resultado Intent.getClipData. Ele tem a matriz de ClipData Item.
Tam Huynh de
71

Defina essas variáveis ​​na classe:

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

Vamos supor que onClick em um botão deve abrir a galeria para selecionar imagens

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

Então você deve substituir o 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);
}

NOTE QUE: a galeria não oferece a capacidade de selecionar várias imagens, portanto, aqui abrimos todos os estúdios de imagens em que você pode selecionar várias imagens. e não se esqueça de adicionar as permissões ao seu manifesto

MUITO IMPORTANTE: getData (); para obter uma única imagem e eu a armazenei aqui em imageEncoded String se o usuário selecionar várias imagens, então elas devem ser armazenadas na lista

Então você tem que verificar qual é nulo para usar o outro

Desejo que você tenha uma boa tentativa e para os outros

Laith Mihyar
fonte
Eu pulei o "intent.setType (" image / * ");" e envia os usuários diretamente para Foto em vez de dar ao usuário a chance de ir para a Galeria, que não permite a seleção de várias fotos. Não tenho certeza se é por causa disso, meu getData () nunca retorna nulo, então acabei usando getClipData exclusivamente para seleção de imagem única e múltipla.
Johnny Wu
1
basta usar a parte data.getClipData () é suficiente, não há necessidade de verificar data.getData ()
truongnm
&& null! = dados ??
Dia
8
Uri uri = content: //com.android.providers.media.documents/document/image%3A772 uri tem dados, mas cursor.getString retorna null para mim imageEncoded = cursor.getString (columnIndex);
Muhammad Zubair Ashraf
2
Foi útil, mas eu tive que complementar com essas funções para getPath: stackoverflow.com/a/20559175/6141959
Geynen
31

Muitas dessas respostas têm semelhanças, mas estão faltando a parte mais importante que está onActivityResult, verifique se data.getClipDataé nulo antes de verificardata.getData

O código para chamar o seletor de arquivos:

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

O código para obter todas as imagens selecionadas:

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

Observe que o seletor do Android tem Fotos e Galeria disponíveis em alguns dispositivos. Fotos permite que várias imagens sejam selecionadas. A galeria permite apenas um de cada vez.

Mira_Cole
fonte
o que é getClipData ()? data.getData não é suficiente?
adi
1
Em alguns dispositivos Samsung, os resultados serão diferentes dos de dispositivos não Samsung. Se o usuário selecionar vários arquivos, getData()às vezes NÃO será nulo, mas terá apenas um Uri. Se você deseja controlar quando um usuário seleciona vários arquivos, verifique getClipData()antes getData()- se os dados do clipe não forem nulos, o usuário pode ter selecionado várias imagens. O manuseio de getClipData antes de getData, mas o manuseio de ambos os casos, é importante para oferecer suporte a diferentes dispositivos e, ao mesmo tempo, permitir vários Uris.
Mira_Cole de
@Mira_Code Como posso definir as imagens selecionadas para diferentes visualizações de imagem.
Hasnain Ghias
20

Espero que essa resposta não seja tarde. Porque o widget da galeria não suporta seleção múltipla por padrão, mas você pode customizar o gridview que aceitou sua intenção multisseleção. A outra opção é estender a visualização da galeria e adicionar seu próprio código para permitir a seleção múltipla.
Esta é a biblioteca simples que pode fazer: https://github.com/luminousman/MultipleImagePick

Atualização :
A partir de @ ilsy comentário, CustomGalleryActivity neste uso da biblioteca manageQuery, que está obsoleto, por isso deve ser alterado para getContentResolver().query()e cursor.close()como esta resposta

R4j
fonte
@ R4j Sim e escrevi sobre isso: a biblioteca não está pronta para ser usada em projetos. Precisa de muitas atualizações para começar a usá-lo. E sobre sua atualização: não use getContentResolver().query()em thread de interface do usuário. Leia sobre Carregadores e Biblioteca de Suporte.
mbelsky de
.cacheOnDisc()também descontinuado, portanto, altere-o para .cacheOnDisc(true)com parâmetro booleano
Pratik Butani
5

Inicializar instância:

private String imagePath;
private List<String> imagePathList;

Em onActivityResult, você deve escrever este bloco If-else 2. Um para uma única imagem e outro para várias imagens.

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

A parte mais importante, obter o caminho da imagem do 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 isso possa ajudá-lo.

Hasib Akter
fonte
1

Eu obtive null do Cursor. Então encontrei uma solução para converter o Uriem Bitmapque funcione perfeitamente.

Aqui está a solução que funciona para mim:

@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
fonte
0

O código abaixo está funcionando bem.

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

Você quer mais esclarecimentos. http://mylearnandroid.blogspot.in/2014/02/multiple-choose-custom-gallery.html

Ramesh Thangaraj
fonte
1
se funcionar, está bem. É bom apontar o código obsoleto, mas contanto que você o esteja usando sem problemas, não há problema em usar. É importante saber por que está obsoleto, se são problemas de segurança, o código mais recente é mais eficiente, etc. Mas, como os aplicativos Android são compatíveis com versões futuras, o código obsoleto ainda funcionará no futuro.
JStephen
0

Eu também tive o mesmo problema. Eu também queria que os usuários pudessem tirar fotos facilmente enquanto escolhem as fotos da galeria. Não consegui encontrar uma maneira nativa de fazer isso, portanto decidi fazer um projeto de código aberto. É muito parecido com MultipleImagePick, mas apenas uma maneira melhor de implementá-lo.

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
fonte
0

Experimente este IntentChooser . Basta adicionar algumas linhas de código, eu fiz o resto para você.

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

PS: conforme mencionado nas respostas acima, EXTRA_ALLOW_MULTIPLE está disponível apenas para API> = 18. E alguns aplicativos de galeria não disponibilizam esse recurso (Google Fotos e Documentos ( com.android.documentsui) funcionam.

Tuan Chau
fonte
Não me permitindo escolher várias imagens, embora adicionadasintent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
Scorpion