Come scegliere un'immagine dalla galleria (scheda SD) per la mia app?


343

Questa domanda è stata originariamente posta per Android 1.6.

Sto lavorando su opzioni di foto nella mia app.

Ho un pulsante e un ImageView nella mia attività. Quando faccio clic sul pulsante verrebbe reindirizzato alla galleria e sarei in grado di selezionare un'immagine. L'immagine selezionata appare nel mio ImageView.


1
guarda questa risposta, ho pubblicato lì un codice migliorato per gestire le scelte dei file manager anche stackoverflow.com/questions/2169649/…
mad

Risposte:


418

Risposta aggiornata, circa 5 anni dopo:

Il codice nella risposta originale non funziona più in modo affidabile, poiché le immagini da varie fonti a volte restituiscono con un URI di contenuto diverso, ovvero content://anziché file://. Una soluzione migliore è semplicemente usarecontext.getContentResolver().openInputStream(intent.getData()) , poiché ciò restituirà un InputStream che è possibile gestire come si sceglie.

Per esempio, BitmapFactory.decodeStream() funziona perfettamente in questa situazione, poiché è anche possibile utilizzare i campi Opzioni e Dimensioni campione per sottocampionare immagini di grandi dimensioni ed evitare problemi di memoria.

Tuttavia, cose come Google Drive restituiscono gli URI alle immagini che non sono ancora state scaricate. Pertanto è necessario eseguire il codice getContentResolver () su un thread in background.


Risposta originale:

Le altre risposte hanno spiegato come inviare l'intento, ma non hanno spiegato bene come gestire la risposta. Ecco un codice di esempio su come farlo:

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

Dopo questo, hai l'immagine selezionata memorizzata in "yourSelectedImage" per fare quello che vuoi. Questo codice funziona ottenendo la posizione dell'immagine nel database ContentResolver, ma da solo non è sufficiente. Ogni immagine ha circa 18 colonne di informazioni, che vanno dal suo percorso file alla "data dell'ultima modifica" alle coordinate GPS del luogo in cui è stata scattata la foto, sebbene molti campi non siano effettivamente utilizzati.

Per risparmiare tempo poiché in realtà non sono necessari gli altri campi, la ricerca del cursore viene eseguita con un filtro. Il filtro funziona specificando il nome della colonna desiderata, MediaStore.Images.Media.DATA, che è il percorso, quindi assegnando quella stringa [] alla query del cursore. La query del cursore ritorna con il percorso, ma non si conosce in quale colonna si trova fino a quando non si utilizza il columnIndexcodice. Questo semplicemente ottiene il numero della colonna in base al suo nome, lo stesso usato nel processo di filtraggio. Una volta ottenuto questo, sei finalmente in grado di decodificare l'immagine in una bitmap con l'ultima riga di codice che ho fornito.


4
cursore.moveToFirst () dovrebbe essere verificato per l'esistenza: if (cursor.moveToFirst ()) {fare qualcosa con i dati del cursore}
mishkin

14
Invece del cursore dovresti ottenere l'immagine in questo modo: Bitmap b = MediaStore.Images.Media.getBitmap (this.getContentResolver (), selectedImage);
Luigi Agosti,

4
Luigi, se Bitmap è di grandi dimensioni MediaStore.Images.Media.getBitmap () può causare eccezioni OutOfMemory. Il metodo di Steve consente di ridimensionare l'immagine prima di caricarla in memoria.
Frank Harper,

9
questo non funziona per me, ottengo un valore null da cursor.getString (columnIndex);
Alexis Pautrot,

9
Attento a questo metodo: il nome file sarà "null" quando l'utente seleziona una foto da un album di Picasa o dall'app Google+ Foto.
Ciske Boekelo,

315
private static final int SELECT_PHOTO = 100;

Inizia intento

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

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

In alternativa, puoi anche sottocampionare l'immagine per evitare errori 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);

    }

8
inserendo un jpeg da 1,5 MB nel mio piccolo imageview 100px per 100px si è verificato un errore di memoria insufficiente della VM. Il downsampling ha risolto il problema :-)
Someone Somewhere

1
Ciao. Entrambi i flussi non dovrebbero essere chiusi?
Denis Kniazhev,

Ciao @ siamii..ho seguito il tuo codice..ma funziona parzialmente per me .. :( quando l'immagine è selezionata dalla galleria nella sezione immagini catturate, allora sta dando un errore json, ma quando l'immagine è selezionata dalla galleria nella sezione bluetooth immagine si accede e inviato al server..could si prega di controllare questo link e mi suggeriscono qualsiasi soluzione si prega ... stackoverflow.com/questions/29234409/image-is-not-uploaded
Prabs

La sezione sulla ricerca della scala potrebbe essere scritta come:int scale = 1; for ( ; bfOptions.outWidth / scale > TARGET_SIZE && bfOptions.outWidth > TARGET_SIZE; scale*=2);
The_Rafi

@siamii Dove e come chiamare questo metodo -------- decodeUri
Akshay Kumar

87

Devi avviare l'intento della galleria per un risultato.

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

Quindi onActivityForResult, chiama intent.getData()per ottenere l'URI dell'immagine. Quindi è necessario ottenere l'immagine dal ContentProvider.


In che modo ACTION_PICK differisce da ACTION_GET_CONTENT utilizzato in altre due risposte?
penguin359,

4
Con ACTION_PICK specifichi un URI specifico e con ACTION_GET_CONTENT specifichi un mime_type. Ho usato ACTION_PICK perché la domanda riguardava specificamente le immagini della SDCARD e non tutte le immagini.
Robby Pond,

2
Freddo. Questo è esattamente ciò di cui avevo bisogno e funzionava come un fascino :) Mi chiedo da dove voi ragazzi trovate questa roba :)
Jayshil Dave,

@WilliamKinaan ACTIVITY_SELECT_IMAGE è qualsiasi valore int che specifichi per identificare il risultato che ti aspetti di ricevere. Viene quindi rispedito in onActivityResult (int requestCode, int resultCode, Intent data) come 'requestCode'.
Fydo,

@Fydo mi sono reso conto che più tardi, grazie
William Kinaan,

22

Ecco un codice testato per immagini e video che funzionerà per tutte le API meno di 19 e anche più di 19.

Immagine:

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

Video:

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

14

Fai questo per avviare la galleria e consentire all'utente di scegliere un'immagine:

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

Quindi nel tuo onActivityResult()uso l'URI dell'immagine che viene restituita per impostare l'immagine su ImageView.


3
Questo non funzionerà per i dispositivi Android 4.4. Avvierà la schermata dei documenti recenti.
Noundla Sandeep,

2
Ecco una correzione per KitKat:
stackoverflow.com/a/26690628/860488

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

}

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

}

Ecco una correzione per KitKat:
stackoverflow.com/a/26690628/860488

4

Per alcuni motivi, tutte le risposte in questo thread, nel onActivityResult()tentativo di postelaborare il ricevuto Uri, come ottenere il vero percorso dell'immagine e quindi utilizzare BitmapFactory.decodeFile(path)per ottenere il Bitmap.

Questo passaggio non è necessario. La ImageViewclasse ha un metodo chiamato setImageURI(uri). Passaci il tuo uri e dovresti aver finito.

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

Per un esempio di lavoro completo puoi dare un'occhiata qui: http://androidbitmaps.blogspot.com/2015/04/loading-images-in-android-part-iii-pick.html

PS:
Ottenere Bitmapin una variabile separata avrebbe senso nei casi in cui l'immagine da caricare è troppo grande per adattarsi alla memoria, ed è necessaria un'operazione di ridimensionamento per impedire OurOfMemoryError, come mostrato nella risposta @siamii.


3

chiama scegli Metodo immagine come-

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

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


}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.