Wie wähle ich ein Bild aus der Galerie (SD-Karte) für meine App aus?

343

Diese Frage wurde ursprünglich für Android 1.6 gestellt.

Ich arbeite an Fotooptionen in meiner App.

Ich habe eine Schaltfläche und eine Bildansicht in meiner Aktivität. Wenn ich auf die Schaltfläche klicke, wird sie zur Galerie weitergeleitet und ich kann ein Bild auswählen. Das ausgewählte Bild wird in meiner ImageView angezeigt.

Praveen
quelle
1
Schauen Sie sich diese Antwort an, ich habe dort einen verbesserten Code gepostet, um Picks von Dateimanagern zu verarbeiten. Auch stackoverflow.com/questions/2169649/…
mad

Antworten:

418

Aktualisierte Antwort, fast 5 Jahre später:

Der Code in der ursprünglichen Antwort funktioniert nicht mehr zuverlässig, da Bilder aus verschiedenen Quellen manchmal mit einem anderen Inhalts-URI zurückgegeben werden, dh content://nicht file://. Eine bessere Lösung ist die einfache Verwendung context.getContentResolver().openInputStream(intent.getData()), da dadurch ein InputStream zurückgegeben wird, den Sie nach Belieben verarbeiten können.

Funktioniert beispielsweise BitmapFactory.decodeStream()in dieser Situation einwandfrei, da Sie dann auch das Feld Optionen und inSampleSize verwenden können, um große Bilder herunterzusampeln und Speicherprobleme zu vermeiden.

Dinge wie Google Drive geben jedoch URIs an Bilder zurück, die noch nicht heruntergeladen wurden. Daher müssen Sie den Code getContentResolver () für einen Hintergrundthread ausführen.


Ursprüngliche Antwort:

Die anderen Antworten erklärten, wie man die Absicht sendet, aber sie erklärten nicht gut, wie man mit der Antwort umgeht. Hier ist ein Beispielcode dafür:

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

Danach haben Sie das ausgewählte Bild in "yourSelectedImage" gespeichert, um zu tun, was Sie wollen. Dieser Code ermittelt den Speicherort des Bildes in der ContentResolver-Datenbank. Dies allein reicht jedoch nicht aus. Jedes Bild enthält ungefähr 18 Informationsspalten, angefangen vom Dateipfad über das Datum der letzten Änderung bis hin zu den GPS-Koordinaten, an denen das Foto aufgenommen wurde, obwohl viele der Felder nicht tatsächlich verwendet werden.

Um Zeit zu sparen, da Sie die anderen Felder nicht benötigen, wird die Cursorsuche mit einem Filter durchgeführt. Der Filter gibt den Namen der gewünschten Spalte an, MediaStore.Images.Media.DATA, den Pfad, und gibt diese Zeichenfolge [] an die Cursorabfrage weiter. Die Cursorabfrage wird mit dem Pfad zurückgegeben, aber Sie wissen nicht, in welcher Spalte sie sich befindet, bis Sie den columnIndexCode verwenden. Dadurch wird einfach die Nummer der Spalte basierend auf ihrem Namen ermittelt, die auch im Filterprozess verwendet wird. Sobald Sie das haben, können Sie das Bild mit der letzten Codezeile, die ich gegeben habe, endlich in eine Bitmap dekodieren.

Steve Haley
quelle
4
cursor.moveToFirst () sollte auf Existenz überprüft werden: if (cursor.moveToFirst ()) {etwas mit
Cursordaten machen
14
Anstelle des Cursors sollten Sie das Bild folgendermaßen abrufen: Bitmap b = MediaStore.Images.Media.getBitmap (this.getContentResolver (), selectedImage);
Luigi Agosti
4
Luigi, wenn die Bitmap groß ist MediaStore.Images.Media.getBitmap () kann OutOfMemory-Ausnahmen verursachen. Steves Methode ermöglicht es, das Bild zu verkleinern, bevor es in den Speicher geladen wird.
Frank Harper
9
Dies funktioniert bei mir nicht. Ich erhalte eine Null von cursor.getString (columnIndex).
Alexis Pautrot
9
Vorsicht bei dieser Methode: Der Dateiname ist "null", wenn der Benutzer ein Foto aus einem Picasa-Album oder aus der Google+ Fotos-App auswählt.
Ciske Boekelo
315
private static final int SELECT_PHOTO = 100;

Absicht starten

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

Ergebnis verarbeiten

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

Alternativ können Sie Ihr Bild auch verkleinern, um OutOfMemory-Fehler zu vermeiden.

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
quelle
8
Das Einfügen eines 1,5-MB-JPEG in meine kleine 100px x 100px-Bildansicht führte zu einem VM-Speicherfehler. Downsampling hat dieses Problem behoben :-)
Jemand irgendwo
1
Hallo. Sollten nicht beide Streams geschlossen sein?
Denis Kniazhev
Hallo @ siamii..Ich bin deinem Code gefolgt..aber es funktioniert teilweise für mich .. :( Wenn das Bild aus der Galerie im Bereich für aufgenommene Bilder ausgewählt wird, gibt es einen JSON-Fehler, aber wenn das Bild aus der Galerie im Bereich für Bluetooth ausgewählt wird Das Bild wird abgerufen und an den Server gesendet. Könnten Sie bitte diesen Link überprüfen und mir eine Lösung vorschlagen ... stackoverflow.com/questions/29234409/image-is-not-uploaded
Prabs
Der Abschnitt über das Finden der Skala könnte geschrieben werden als:int scale = 1; for ( ; bfOptions.outWidth / scale > TARGET_SIZE && bfOptions.outWidth > TARGET_SIZE; scale*=2);
The_Rafi
@siamii Wo und wie man diese Methode aufruft -------- decodeUri
Akshay Kumar
87

Sie müssen die Galerie-Absicht für ein Ergebnis starten.

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

Dann onActivityForResultrufen Sie intent.getData()die Uri des Bildes zu erhalten. Dann müssen Sie das Bild vom ContentProvider abrufen.

Robby Pond
quelle
Wie unterscheidet sich ACTION_PICK von ACTION_GET_CONTENT, das in zwei anderen Antworten verwendet wird?
Pinguin359
4
Mit ACTION_PICK geben Sie einen bestimmten URI an und mit ACTION_GET_CONTENT geben Sie einen mime_type an. Ich habe ACTION_PICK verwendet, da es sich bei der Frage speziell um Bilder von der SDCARD und nicht um alle Bilder handelte.
Robby Pond
2
Cool. Dies ist genau das, was ich brauchte und arbeitete wie ein Zauber :)
Ich frage
@WilliamKinaan ACTIVITY_SELECT_IMAGE ist ein beliebiger int-Wert, den Sie angeben, um zu ermitteln, welches Ergebnis Sie erwarten. Es wird dann in onActivityResult (int requestCode, int resultCode, Intent data) als 'requestCode' zurückgesendet.
Fydo
@Fydo Ich erkannte, dass später, Danke
William Kinaan
22

Hier ist ein getesteter Code für Bild und Video. Er funktioniert auch für alle APIs unter 19 und über 19.

Bild:

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();
        }
Muhammad Umair Shafique
quelle
14

Führen Sie dies aus, um die Galerie zu starten und dem Benutzer die Auswahl eines Bildes zu ermöglichen:

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

onActivityResult()Verwenden Sie dann in Ihrer Verwendung die URI des zurückgegebenen Bilds, um das Bild in Ihrer ImageView festzulegen.

Mark B.
quelle
3
Dies funktioniert nicht für Android 4.4-Geräte. Der Bildschirm mit den zuletzt verwendeten Dokumenten wird geöffnet.
Noundla Sandeep
2
Hier ist ein Fix für 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);
}

}
Blatt mehr
quelle
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
quelle
Hier ist ein Fix für KitKat: stackoverflow.com/a/26690628/860488
Morten Holmgaard
4

Aus bestimmten Gründen onActivityResult()versuchen alle Antworten in diesem Thread, das Empfangene nachzubearbeiten, z. UriB. den tatsächlichen Pfad des Bildes abzurufen und dann zu verwenden BitmapFactory.decodeFile(path), um das zu erhalten Bitmap.

Dieser Schritt ist nicht erforderlich. Die ImageViewKlasse hat eine Methode namens setImageURI(uri). Gib dein Uri weiter und du solltest fertig sein.

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

Ein vollständiges Arbeitsbeispiel finden Sie hier: http://androidbitmaps.blogspot.com/2015/04/loading-images-in-android-part-iii-pick.html

PS: Das
Einfügen Bitmapin eine separate Variable ist in Fällen sinnvoll, in denen das zu ladende Bild zu groß ist, um in den Speicher zu passen, und eine OurOfMemoryErrorVerkleinerung erforderlich ist, um dies zu verhindern , wie in der @ siiamii-Antwort gezeigt.

Andy Res
quelle
3

Rufen Sie die Methode selectImage auf.

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
quelle
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
quelle