348 Stimmen

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

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

Ich arbeite an den Fotooptionen in meiner App.

In meiner Aktivität habe ich einen Button und ein ImageView. Wenn ich auf den Button klicke, wird die Galerie geöffnet und ich kann ein Bild auswählen. Das ausgewählte Bild wird dann im ImageView angezeigt.

1 Stimmen

Schau dir diese Antwort an, dort habe ich einen verbesserten Code gepostet, um auch Auswahl aus Dateimanagern zu verarbeiten stackoverflow.com/questions/2169649/…

419voto

Steve Haley Punkte 54674

Aktualisierte Antwort, fast 5 Jahre später:

Der Code in der Originalantwort funktioniert nicht mehr zuverlässig, da Bilder aus verschiedenen Quellen manchmal mit einer anderen Inhalts-URI zurückkehren, d.h. content:// anstelle von file://. Eine bessere Lösung ist einfach context.getContentResolver().openInputStream(intent.getData()) zu verwenden, da dies einen InputStream zurückgibt, den Sie nach Belieben verarbeiten können.

Zum Beispiel funktioniert BitmapFactory.decodeStream() perfekt in dieser Situation, da Sie auch die Optionen und das inSampleSize-Feld verwenden können, um große Bilder zu verkleinern und Speicherprobleme zu vermeiden.

Allerdings liefern Dienste wie Google Drive URIs zu Bildern zurück, die noch nicht tatsächlich heruntergeladen wurden. Daher müssen Sie den getContentResolver() Code in einem Hintergrundthread ausführen.


Ursprüngliche Antwort:

Die anderen Antworten haben erklärt, wie man das Intent sendet, aber sie haben nicht gut erklärt, wie man die Antwort verarbeitet. Hier ist ein Beispielcode, wie das gemacht werden kann:

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

Nach diesem Schritt haben Sie das ausgewählte Bild in "yourSelectedImage" gespeichert, um damit zu tun, was Sie möchten. Dieser Code funktioniert, indem er den Speicherort des Bildes in der ContentResolver-Datenbank abruft, aber allein das reicht nicht aus. Jedes Bild hat ungefähr 18 Spalten Informationen, von seinem Dateipfad bis zum 'Datum der letzten Änderung' bis zu den GPS-Koordinaten, wo das Foto aufgenommen wurde, obwohl viele der Felder tatsächlich nicht verwendet werden.

Um Zeit zu sparen, da Sie die anderen Felder nicht wirklich benötigen, wird eine Cursor-Suche mit einem Filter durchgeführt. Der Filter funktioniert, indem der Name der gewünschten Spalte angegeben wird, MediaStore.Images.Media.DATA, das ist der Pfad, und dann wird dieses string[] der Cursor-Abfrage übergeben. Die Cursor-Abfrage gibt den Pfad zurück, aber Sie wissen nicht, in welcher Spalte er sich befindet, bis Sie den columnIndex Code verwenden. Dieser bekommt einfach die Nummer der Spalte basierend auf ihrem Namen, derselbe, der im Filterungsprozess verwendet wurde. Wenn Sie das haben, sind Sie endlich in der Lage, das Bild in ein Bitmap mit der letzten Zeile des Codes zu dekodieren, den ich gegeben habe.

4 Stimmen

Cursor.moveToFirst() sollte auf Existenz überprüft werden: if (cursor.moveToFirst()) {tue etwas mit den Cursor-Daten}

0 Stimmen

ColumnIndex ist immer 0, weil Ihre Abfrage nur nach einer Spalte fragt, die natürlich den Index 0 hat. Oder habe ich etwas übersehen und das ist nicht immer der Fall?

1 Stimmen

Es ist nichts, mit dem ich besonders experimentiert habe, also kann ich das nicht mit Sicherheit sagen. Es würde Sinn machen, dass wenn du nur nach einer Spalte fragst, du davon ausgehen kannst, dass sie immer an Index 0 sein wird. Jedoch denke ich, dass zur Sicherheit, falls du etwas änderst, diese eine Zeile es wert ist.

317voto

siamii Punkte 21999
private static final int SELECT_PHOTO = 100;

Starte Intent

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

Verarbeite Ergebnis

@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 kannst du auch dein Bild verkleinern, um OutOfMemory-Fehler zu vermeiden.

private Bitmap decodeUri(Uri selectedImage) throws FileNotFoundException {

        // Bildgröße decodieren
        BitmapFactory.Options o = new BitmapFactory.Options();
        o.inJustDecodeBounds = true;
        BitmapFactory.decodeStream(getContentResolver().openInputStream(selectedImage), null, o);

        // Die neue Größe, zu der wir skalieren möchten
        final int ERFORDERLICHE_GRÖßE = 140;

        // Richtigen Skalierungsfaktor finden. Er sollte eine Zweierpotenz sein.
        int width_tmp = o.outWidth, height_tmp = o.outHeight;
        int scale = 1;
        while (true) {
            if (width_tmp / 2 < ERFORDERLICHE_GRÖßE
               || height_tmp / 2 < ERFORDERLICHE_GRÖßE) {
                break;
            }
            width_tmp /= 2;
            height_tmp /= 2;
            scale *= 2;
        }

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

    }

8 Stimmen

Das Einfügen eines 1,5 MB großen JPEGs in meine kleine 100px mal 100px ImageView führte zu einem VM-Speicherfehler. Durch Downsampling wurde dieses Problem behoben :-)

1 Stimmen

Hallo. Sollten nicht beide Streams geschlossen werden?

0 Stimmen

Hallo @siamii..Ich habe deinen Code befolgt.. aber er funktioniert teilweise für mich.. :( wenn das Bild aus der Galerie unter dem Abschnitt 'erfasste Bilder' ausgewählt wird, wird ein JSON-Fehler angezeigt, aber wenn das Bild aus der Galerie unter dem Abschnitt 'bluetooth' ausgewählt wird, wird das Bild aufgerufen und an den Server gesendet.. könntest du bitte diesen link überprüfen und mir bitte eine Lösung vorschlagen... stackoverflow.com/questions/29234409/image-is-not-uploaded

87voto

Robby Pond Punkte 71994

Sie müssen die Galerie-Absicht starten, um ein Ergebnis zu erhalten.

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

Dann in onActivityForResult, rufen Sie intent.getData() auf, um die Uri des Bildes zu erhalten. Dann müssen Sie das Bild vom ContentProvider abrufen.

0 Stimmen

Wie unterscheidet sich ACTION_PICK von ACTION_GET_CONTENT, die in zwei anderen Antworten verwendet wurden?

4 Stimmen

Mit ACTION_PICK geben Sie eine spezifische URI an und mit ACTION_GET_CONTENT geben Sie einen mime_type an. Ich habe ACTION_PICK verwendet, weil die Frage speziell nach Bildern von der SDCARD und nicht nach allen Bildern gefragt war.

2 Stimmen

Cool. Das ist genau das, was ich brauchte und hat super funktioniert :) Ich frage mich, woher ihr all diese Dinge findet :)

23voto

Hier ist ein getesteter Code für Bild und Video. Es funktioniert für alle APIs kleiner als 19 und größer als 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();
        }

14voto

Mark B Punkte 154748

Um die Galerie zu starten und es dem Benutzer zu ermöglichen, ein Bild auszuwählen, tun Sie dies:

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

Dann verwenden Sie in Ihrem onActivityResult() die URI des zurückgegebenen Bildes, um das Bild auf Ihrem ImageView zu setzen.

3 Stimmen

Dies funktioniert nicht für die Android 4.4-Geräte. Es wird den Bildschirm mit den zuletzt geöffneten Dokumenten starten.

2 Stimmen

Hier ist eine Lösung für KitKat: stackoverflow.com/a/26690628/860488

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X