Como escolher uma imagem da galeria (cartão SD) para o meu aplicativo?

343

Esta pergunta foi originalmente feita para Android 1.6.

Estou trabalhando nas opções de fotos no meu aplicativo.

Eu tenho um botão e um ImageView na minha atividade. Quando clico no botão, ele é redirecionado para a galeria e eu posso selecionar uma imagem. A imagem selecionada apareceria no meu ImageView.

Praveen
fonte
11
olhar para esta resposta, eu postei um código melhorado lá para picaretas alça de gerenciadores de arquivos também stackoverflow.com/questions/2169649/...
louco

Respostas:

418

Resposta atualizada, quase 5 anos depois:

O código na resposta original não funciona mais de maneira confiável, pois imagens de várias fontes às vezes retornam com um URI de conteúdo diferente, ou seja, em content://vez de file://. Uma solução melhor é simplesmente usar context.getContentResolver().openInputStream(intent.getData()), pois isso retornará um InputStream que você pode manipular conforme desejar.

Por exemplo, BitmapFactory.decodeStream()funciona perfeitamente nessa situação, pois você também pode usar o campo Opções e inSampleSize para reduzir a amostragem de imagens grandes e evitar problemas de memória.

No entanto, coisas como o Google Drive retornam URIs para imagens que ainda não foram realmente baixadas. Portanto, você precisa executar o código getContentResolver () em um encadeamento em segundo plano.


Resposta original:

As outras respostas explicaram como enviar a intenção, mas não explicaram bem como lidar com a resposta. Aqui está um exemplo de código sobre como fazer isso:

protected void onActivityResult(int requestCode, int resultCode, 
       Intent imageReturnedIntent) {
    super.onActivityResult(requestCode, resultCode, imageReturnedIntent); 

    switch(requestCode) { 
    case REQ_CODE_PICK_IMAGE:
        if(resultCode == RESULT_OK){  
            Uri selectedImage = imageReturnedIntent.getData();
            String[] filePathColumn = {MediaStore.Images.Media.DATA};

            Cursor cursor = getContentResolver().query(
                               selectedImage, filePathColumn, null, null, null);
            cursor.moveToFirst();

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


            Bitmap yourSelectedImage = BitmapFactory.decodeFile(filePath);
        }
    }
}

Depois disso, você terá a imagem selecionada armazenada em "yourSelectedImage" para fazer o que quiser. Esse código funciona obtendo a localização da imagem no banco de dados ContentResolver, mas isso por si só não é suficiente. Cada imagem possui cerca de 18 colunas de informações, desde o caminho do arquivo até a data da última modificação, até as coordenadas GPS de onde a foto foi tirada, embora muitos dos campos não sejam realmente usados.

Para economizar tempo, já que você não precisa dos outros campos, a pesquisa do cursor é feita com um filtro. O filtro funciona especificando o nome da coluna desejada, MediaStore.Images.Media.DATA, que é o caminho e, em seguida, atribuindo essa sequência [] à consulta do cursor. A consulta do cursor retorna com o caminho, mas você não sabe em qual coluna está até usar o columnIndexcódigo. Isso simplesmente obtém o número da coluna com base em seu nome, o mesmo usado no processo de filtragem. Quando você conseguir isso, finalmente poderá decodificar a imagem em um bitmap com a última linha de código que eu forneci.

Steve Haley
fonte
4
cursor.moveToFirst () deve ser verificado para a existência: if (cursor.moveToFirst ()) {fazer algo com dados cursor}
Mishkin
14
Em vez do cursor, você deve obter a imagem desta maneira: Bitmap b = MediaStore.Images.Media.getBitmap (this.getContentResolver (), selectedImage);
Luigi Agosti 27/03
4
Luigi, se o Bitmap for grande MediaStore.Images.Media.getBitmap () pode causar exceções OutOfMemory. O método de Steve permite reduzir a imagem antes de carregá-la na memória.
31712 Frank
9
isso não está funcionando para mim, recebo um nulo de cursor.getString (columnIndex);
Alexis Pautrot
9
Cuidado com este método: o nome do arquivo será 'nulo' quando o usuário selecionar uma foto de um álbum do Picasa ou do aplicativo Fotos do Google+.
Ciske Boekelo
315
private static final int SELECT_PHOTO = 100;

Intenção de início

Intent photoPickerIntent = new Intent(Intent.ACTION_PICK);
photoPickerIntent.setType("image/*");
startActivityForResult(photoPickerIntent, SELECT_PHOTO);    

Resultado do processo

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent imageReturnedIntent) { 
    super.onActivityResult(requestCode, resultCode, imageReturnedIntent); 

    switch(requestCode) { 
    case SELECT_PHOTO:
        if(resultCode == RESULT_OK){  
            Uri selectedImage = imageReturnedIntent.getData();
            InputStream imageStream = getContentResolver().openInputStream(selectedImage);
            Bitmap yourSelectedImage = BitmapFactory.decodeStream(imageStream);
        }
    }
}

Como alternativa, você também pode reduzir a amostra da imagem para evitar erros de OutOfMemory.

private Bitmap decodeUri(Uri selectedImage) throws FileNotFoundException {

        // Decode image size
        BitmapFactory.Options o = new BitmapFactory.Options();
        o.inJustDecodeBounds = true;
        BitmapFactory.decodeStream(getContentResolver().openInputStream(selectedImage), null, o);

        // The new size we want to scale to
        final int REQUIRED_SIZE = 140;

        // Find the correct scale value. It should be the power of 2.
        int width_tmp = o.outWidth, height_tmp = o.outHeight;
        int scale = 1;
        while (true) {
            if (width_tmp / 2 < REQUIRED_SIZE
               || height_tmp / 2 < REQUIRED_SIZE) {
                break;
            }
            width_tmp /= 2;
            height_tmp /= 2;
            scale *= 2;
        }

        // Decode with inSampleSize
        BitmapFactory.Options o2 = new BitmapFactory.Options();
        o2.inSampleSize = scale;
        return BitmapFactory.decodeStream(getContentResolver().openInputStream(selectedImage), null, o2);

    }
siamii
fonte
8
colocar um jpeg de 1,5 MB em minha pequena visualização de imagem de 100 por 100 pixels resultou em erro de falta de memória da VM. Downsampling corrigiu esse problema :-)
Alguém em algum lugar
11
Oi. Os dois fluxos não devem ser fechados?
Denis Kniazhev
Olá @ siamii.Eu segui o seu código ... mas ele está funcionando parcialmente para mim .. :( quando a imagem é selecionada da galeria na seção de imagens capturadas, está dando erro json, mas quando a imagem é selecionada da galeria na seção de bluetooth a imagem é acessada e enviada ao servidor .. você pode verificar este link e sugerir-me qualquer solução, por favor ... stackoverflow.com/questions/29234409/image-is-not-uploaded
Prabs
A seção sobre encontrar a escala poderia ser escrita como:int scale = 1; for ( ; bfOptions.outWidth / scale > TARGET_SIZE && bfOptions.outWidth > TARGET_SIZE; scale*=2);
The_Rafi
@siamii Onde e como chamar esse método -------- decodeURI
Akshay Kumar
87

Você precisa iniciar a intenção da galeria para obter um resultado.

Intent i = new Intent(Intent.ACTION_PICK,
               android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(i, ACTIVITY_SELECT_IMAGE); 

Em seguida onActivityForResult, ligue intent.getData()para obter o Uri da imagem. Então você precisa obter a imagem do ContentProvider.

Robby Pond
fonte
Como ACTION_PICK difere de ACTION_GET_CONTENT usado em duas outras respostas?
Penguin359
4
Com ACTION_PICK, você especifica um URI específico e, com ACTION_GET_CONTENT, especifica um mime_type. Eu usei ACTION_PICK porque a pergunta era especificamente imagens do SDCARD e nem todas as imagens.
Robby Pond
2
Legal. Este é exatamente o que eu precisava e funcionou como um encanto :) maravilha de onde vocês encontrar este material :)
Jayshil Dave
@WilliamKinaan ACTIVITY_SELECT_IMAGE é qualquer valor int que você especificar para identificar qual resultado espera receber. Em seguida, é enviado de volta em onActivityResult (int requestCode, int resultCode, Intent data) como o 'requestCode'.
Fydo 28/05
@Fydo eu percebi que, mais tarde, Graças
William Kinaan
22

Aqui está um código testado para imagem e vídeo. Ele funcionará para todas as APIs com menos de 19 e maiores que 19 também.

Imagem:

if (Build.VERSION.SDK_INT <= 19) {
                        Intent i = new Intent();
                        i.setType("image/*");
                        i.setAction(Intent.ACTION_GET_CONTENT);
                        i.addCategory(Intent.CATEGORY_OPENABLE);
                        startActivityForResult(i, 10);
                    } else if (Build.VERSION.SDK_INT > 19) {
                        Intent intent = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
                        startActivityForResult(intent, 10);
                    }

Vídeo:

if (Build.VERSION.SDK_INT <= 19) {
                        Intent i = new Intent();
                        i.setType("video/*");
                        i.setAction(Intent.ACTION_GET_CONTENT);
                        i.addCategory(Intent.CATEGORY_OPENABLE);
                        startActivityForResult(i, 20);
                    } else if (Build.VERSION.SDK_INT > 19) {
                        Intent intent = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Video.Media.EXTERNAL_CONTENT_URI);
                        startActivityForResult(intent, 20);
                    }    

.

     @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (resultCode == Activity.RESULT_OK) {               
            if (requestCode == 10) {
                Uri selectedImageUri = data.getData();
                String selectedImagePath = getRealPathFromURI(selectedImageUri);
            } else if (requestCode == 20) {
                Uri selectedVideoUri = data.getData();
                String selectedVideoPath = getRealPathFromURI(selectedVideoUri);
            }
        }
     }

     public String getRealPathFromURI(Uri uri) {
            if (uri == null) {
                return null;
            }
            String[] projection = {MediaStore.Images.Media.DATA};
            Cursor cursor = getActivity().getContentResolver().query(uri, projection, null, null, null);
            if (cursor != null) {
                int column_index = cursor
                        .getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
                cursor.moveToFirst();
                return cursor.getString(column_index);
            }
            return uri.getPath();
        }
Muhammad Umair Shafique
fonte
14

Faça isso para iniciar a galeria e permitir que o usuário escolha uma imagem:

Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("image/*");
startActivityForResult(intent, IMAGE_PICK);

Em seu onActivityResult()uso, o URI da imagem retornada para definir a imagem no seu ImageView.

Mark B
fonte
3
Isso não funcionará para os dispositivos Android 4.4. Ele iniciará a tela de documentos recentes.
Noundla Sandeep
2
Aqui está uma correção para o KitKat: stackoverflow.com/a/26690628/860488
Morten Holmgaard:
11
public class EMView extends Activity {
ImageView img,img1;
int column_index;
  Intent intent=null;
// Declare our Views, so we can access them later
String logo,imagePath,Logo;
Cursor cursor;
//YOU CAN EDIT THIS TO WHATEVER YOU WANT
private static final int SELECT_PICTURE = 1;

 String selectedImagePath;
//ADDED
 String filemanagerstring;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    img= (ImageView)findViewById(R.id.gimg1);



    ((Button) findViewById(R.id.Button01))
    .setOnClickListener(new OnClickListener() {

        public void onClick(View arg0) {

            // in onCreate or any event where your want the user to
            // select a file
            Intent intent = new Intent();
            intent.setType("image/*");
            intent.setAction(Intent.ACTION_GET_CONTENT);
            startActivityForResult(Intent.createChooser(intent,
                    "Select Picture"), SELECT_PICTURE);


        }
    });
}

//UPDATED
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (resultCode == Activity.RESULT_OK) {
        if (requestCode == SELECT_PICTURE) {
            Uri selectedImageUri = data.getData();

            //OI FILE Manager
            filemanagerstring = selectedImageUri.getPath();

            //MEDIA GALLERY
            selectedImagePath = getPath(selectedImageUri);


            img.setImageURI(selectedImageUri);

           imagePath.getBytes();
           TextView txt = (TextView)findViewById(R.id.title);
           txt.setText(imagePath.toString());


           Bitmap bm = BitmapFactory.decodeFile(imagePath);

          // img1.setImageBitmap(bm);



        }

    }

}

//UPDATED!
public String getPath(Uri uri) {
String[] projection = { MediaColumns.DATA };
Cursor cursor = managedQuery(uri, projection, null, null, null);
column_index = cursor
        .getColumnIndexOrThrow(MediaColumns.DATA);
cursor.moveToFirst();
 imagePath = cursor.getString(column_index);

return cursor.getString(column_index);
}

}
Sheetal Mais
fonte
8
public class BrowsePictureActivity extends Activity {
private static final int SELECT_PICTURE = 1;

private String selectedImagePath;

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    ((Button) findViewById(R.id.Button01))
            .setOnClickListener(new OnClickListener() {

                public void onClick(View arg0) {

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

public void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (resultCode == RESULT_OK) {
        if (requestCode == SELECT_PICTURE) {
            Uri selectedImageUri = data.getData();
            selectedImagePath = getPath(selectedImageUri);
        }
    }
}

public String getPath(Uri uri) {

        if( uri == null ) {
            return null;
        }

        // this will only work for images selected from gallery
        String[] projection = { MediaStore.Images.Media.DATA };
        Cursor cursor = managedQuery(uri, projection, null, null, null);
        if( cursor != null ){
            int column_index = cursor
            .getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
            cursor.moveToFirst();
            return cursor.getString(column_index);
        }

        return uri.getPath();
}

}
Muhammad Usman Ghani
fonte
Aqui está uma correção para o KitKat: stackoverflow.com/a/26690628/860488
Morten Holmgaard:
4

Por algumas razões, todas as respostas neste tópico, na onActivityResult()tentativa de pós-processar o recebido Uri, como obter o caminho real da imagem e depois usá BitmapFactory.decodeFile(path)-lo para obter o Bitmap.

Esta etapa é desnecessária. A ImageViewclasse tem um método chamado setImageURI(uri). Passe seu uri para ele e você deve terminar.

Uri imageUri = data.getData();
imageView.setImageURI(imageUri);

Para um exemplo de trabalho completo, você pode dar uma olhada aqui: http://androidbitmaps.blogspot.com/2015/04/loading-images-in-android-part-iii-pick.html

PS:
Obter Bitmapuma variável separada faria sentido nos casos em que a imagem a ser carregada é muito grande para caber na memória, e é necessária uma operação de redução para evitar OurOfMemoryError, como mostrado na resposta @siamii.

Andy Res
fonte
3

chame o método chooseImage como

public void chooseImage(ImageView v)
{
    Intent intent = new Intent(Intent.ACTION_PICK);
    intent.setType("image/*");
    startActivityForResult(intent, SELECT_PHOTO);
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent imageReturnedIntent) {
    // TODO Auto-generated method stub
    super.onActivityResult(requestCode, resultCode, imageReturnedIntent);

    if(imageReturnedIntent != null)
    {
        Uri selectedImage = imageReturnedIntent.getData();
    switch(requestCode) { 
    case SELECT_PHOTO:
        if(resultCode == RESULT_OK)
        {
            Bitmap datifoto = null;
            temp.setImageBitmap(null);
            Uri picUri = null;
            picUri = imageReturnedIntent.getData();//<- get Uri here from data intent
             if(picUri !=null){
               try {
                   datifoto = android.provider.MediaStore.Images.Media.getBitmap(this.getContentResolver(),                                 picUri);
                   temp.setImageBitmap(datifoto);
               } catch (FileNotFoundException e) {
                  throw new RuntimeException(e);
               } catch (IOException e) {
                  throw new RuntimeException(e);
               } catch (OutOfMemoryError e) {
                Toast.makeText(getBaseContext(), "Image is too large. choose other", Toast.LENGTH_LONG).show();
            }

        }
        }
        break;

}
    }
    else
    {
        //Toast.makeText(getBaseContext(), "data null", Toast.LENGTH_SHORT).show();
    }
}
Akshay Paliwal
fonte
1
#initialize in main activity 
    path = Environment.getExternalStorageDirectory()
            + "/images/make_machine_example.jpg"; #
     ImageView image=(ImageView)findViewById(R.id.image);
 //--------------------------------------------------||

 public void FromCamera(View) {

    Log.i("camera", "startCameraActivity()");
    File file = new File(path);
    Uri outputFileUri = Uri.fromFile(file);
    Intent intent = new Intent(
            android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
    intent.putExtra(MediaStore.EXTRA_OUTPUT, outputFileUri);
    startActivityForResult(intent, 1);

}

public void FromCard() {
    Intent i = new Intent(Intent.ACTION_PICK,
            android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
    startActivityForResult(i, 2);
}

 protected void onActivityResult(int requestCode, int resultCode, Intent data) {

    super.onActivityResult(requestCode, resultCode, data);

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

        Uri selectedImage = data.getData();
        String[] filePathColumn = { MediaStore.Images.Media.DATA };

        Cursor cursor = getContentResolver().query(selectedImage,
                filePathColumn, null, null, null);
        cursor.moveToFirst();

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

        bitmap = BitmapFactory.decodeFile(picturePath);
        image.setImageBitmap(bitmap);

        if (bitmap != null) {
            ImageView rotate = (ImageView) findViewById(R.id.rotate);

        }

    } else {

        Log.i("SonaSys", "resultCode: " + resultCode);
        switch (resultCode) {
        case 0:
            Log.i("SonaSys", "User cancelled");
            break;
        case -1:
            onPhotoTaken();
            break;

        }

    }

}

protected void onPhotoTaken() {
    // Log message
    Log.i("SonaSys", "onPhotoTaken");
    taken = true;
    imgCapFlag = true;
    BitmapFactory.Options options = new BitmapFactory.Options();
    options.inSampleSize = 4;
    bitmap = BitmapFactory.decodeFile(path, options);
    image.setImageBitmap(bitmap);


}
ASHISH KUMAR Tiwary
fonte