Выберите несколько изображений из галереи Android

114

Итак, в основном то, что я пытаюсь достичь, - это открыть Galleryв Android и позволить пользователю выбирать multiple images. Сейчас этот вопрос задают часто но я не удовлетворен ответами. В основном потому, что я нашел кое-что интересное в документации в моей среде IDE (я вернусь к этому позже), и поэтому я не хочу использовать специальный адаптер, а только ванильный.

Теперь мой код для выбора одного изображения:

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

Теперь люди на SO и других сайтах скажут вам, что у вас есть 2 варианта:

1) Не использовать, ACTION_GET_CONTENTа ACTION_SEND_MULTIPLEвзамен.
Это не работает. Это соответствует документам для sendingфайлов, а не, retrievingи это именно то, что он делает. При использовании ACTION_SEND_MULTIPLE на моем устройстве открылось окно, в котором я должен выбрать приложение для отправки моих данных. Это не то, что я хочу, поэтому мне интересно, как люди добились этого с помощью этого решения .. Я что-то упускаю?

2) Реализуйте custom Gallery. Теперь это мой последний вариант, который я рассмотрю, потому что imho это не то, что я ищу, потому что я должен сам его стилизовать И почему, черт возьми, вы просто не можете выбрать несколько изображений в ванильной галерее?

Должна быть опция для этого ... Теперь я обнаружил интересную вещь:
я нашел это в описании документации ACTION_GET_CONTENT.

Если вызывающий может обрабатывать несколько возвращаемых элементов (пользователь выполняет множественный выбор), он может указать EXTRA_ALLOW_MULTIPLE, чтобы указать это.

Это довольно интересно. Здесь они ссылаются на вариант использования, когда пользователь может выбрать несколько элементов?

Позже в документации пишут:

Вы можете использовать EXTRA_ALLOW_MULTIPLE, чтобы позволить пользователю выбирать несколько элементов.

Так что это довольно очевидно, правда? Это то, что мне нужно. Но у меня следующий вопрос: где я могу это поставить EXTRA_ALLOW_MULTIPLE? Печально то, что я не могу найти это нигде в руководстве developers.android, а также это не определено как константа в классе INTENT.

Кто-нибудь может мне с этим помочь EXTRA_ALLOW_MULTIPLE?

Дион Сегейн
источник
geekonjava.blogspot.com/2015/10/…
Расскажи мне, как
1
Решение @KyleShank сработало для меня. Настройка EXTRA_ALLOW_MULTIPLEпозволяет выбрать несколько элементов. Получите URI, вызвав getClipData()возвращенное намерение в onActivityResult. Единственная проблема в том, что виджет галереи не позволяет множественный выбор. В этом случае щелчок по любому изображению завершит выбор, и вы сможете получить URI (одного элемента), вызвав getDataвозвращенное намерение
Tanweer Alam

Ответы:

122

Параметр EXTRA_ALLOW_MULTIPLE устанавливается для намерения через метод Intent.putExtra ():

intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);

Ваш код выше должен выглядеть так:

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

Примечание: EXTRA_ALLOW_MULTIPLEопция доступна только в Android API 18 и выше.

Кайл Шэнк
источник
Я знаю это, но, как я упоминаю в своем ответе: «Печально то, что я не могу найти это нигде в руководстве developers.android, а также не определяется ли это как константа в классе INTENT». Моя IDE не распознает Intent.EXTRA_ALLOW_MULTIPLE. У меня установлен уровень API 18. Моя IDE говорит: «EXTRA_ALLOW_MULTIPLE не может быть разрешено или не является полем»
Дион Сегейн
intent.putExtra (Intent.EXTRA_ALLOW_MULTIPLE, истина); используйте эмулятор, не поддерживайте множественный выбор.
qinmiao
11
Его выбор множественного изображения. но как получить URL-адрес изображения из результата действия ????
Джон
4
Это запускает средство выбора изображений и позволяет мне выбирать несколько изображений, но я не знаю, как получить URL-адреса в onActivityResult.
Том Кинкейд
5
Вы можете получить URL-адреса в результате Intent.getClipData. Он имеет массив ClipData Item.
Tam Huynh
71

Определите эти переменные в классе:

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

Предположим, что onClick на кнопке должен открывать галерею для выбора изображений.

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

Затем вы должны переопределить метод 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);
}

ПРИМЕЧАНИЕ: галерея не дает вам возможности выбирать несколько изображений, поэтому здесь мы открываем студию всех изображений, в которой вы можете выбрать из них несколько изображений. и не забудьте добавить разрешения в свой манифест

ОЧЕНЬ ВАЖНО: getData (); чтобы получить одно изображение, и я сохранил его здесь, в imageEncoded String, если пользователь выбирает несколько изображений, они должны быть сохранены в списке

Итак, вы должны проверить, какой из них равен нулю, чтобы использовать другой

Желаю вам удачной попытки и другим

Лейт Михьяр
источник
Я пропустил "intent.setType (" image / * ");" и он отправляет пользователей прямо в фото, вместо того, чтобы дать пользователю возможность перейти в галерею, которая не позволяет выбирать несколько изображений. Не уверен, что из-за этого мой getData () никогда не возвращает null, поэтому в итоге я использовал getClipData исключительно для выбора как одного, так и нескольких изображений.
Johnny Wu
1
просто используйте часть data.getClipData () достаточно, не нужно проверять data.getData ()
truongnm
&& null! = данные ??
Odaym
8
Uri uri = content: //com.android.providers.media.documents/document/image%3A772 uri имеет данные, но cursor.getString возвращает мне значение null imageEncoded = cursor.getString (columnIndex);
Мухаммад Зубаир Ашраф
2
Это было полезно, но мне пришлось добавить эти функции для getPath: stackoverflow.com/a/20559175/6141959
Гейнен 07
31

Многие из этих ответов имеют сходство, но во всех отсутствует самая важная часть, которая находится onActivityResult, проверьте, data.getClipDataявляется ли значение null перед проверкойdata.getData

Код для вызова средства выбора файла:

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

Код для выбора всех изображений:

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

Обратите внимание, что в программе выбора Android на некоторых устройствах доступны фотографии и галерея. Фотографии позволяют выбрать несколько изображений. Галерея позволяет только по одному.

Mira_Cole
источник
что такое getClipData ()? недостаточно data.getData?
ади
1
На некоторых устройствах Samsung результаты будут отличаться от результатов на устройствах других производителей. Если пользователь выбирает несколько файлов, getData()иногда он НЕ будет иметь значение NULL, а будет иметь только один Uri. Если вы хотите обрабатывать, когда пользователь выбирает несколько файлов, проверьте getClipData()перед этим getData()- если данные клипа не равны нулю, пользователь мог выбрать несколько изображений. Обработка getClipData перед getData, но обработка обоих случаев важна для поддержки разных устройств, но при этом позволяет использовать несколько Uris.
Mira_Cole
@Mira_Code Как я могу установить для выбранных изображений разные виды изображений.
Hasnain Ghias
20

Надеюсь, ответ еще не поздно. Поскольку виджет галереи не поддерживает множественный выбор по умолчанию, но вы можете настроить сетку, которая принимает ваше намерение множественного выбора. Другой вариант - расширить представление галереи и добавить свой собственный код, чтобы разрешить множественный выбор.
Это может сделать простая библиотека: https://github.com/luminousman/MultipleImagePick

Обновление :
С @ ilsy замечания, CustomGalleryActivity в этой библиотеке использовании manageQuery, который является устаревшим, поэтому оно должно быть изменено getContentResolver().query()и cursor.close()как этот ответ

R4j
источник
@ R4j Да, и я об этом писал: библиотека не готова для использования в проектах. Нужно много обновлений, чтобы начать его использовать. И по поводу вашего обновления: не используйте getContentResolver().query()в потоке пользовательского интерфейса. Прочтите о загрузчиках и библиотеке поддержки.
mbelsky
.cacheOnDisc()также устарел, поэтому измените его на .cacheOnDisc(true)с логическим параметром
Pratik Butani
5

Инициализировать экземпляр:

private String imagePath;
private List<String> imagePathList;

В onActivityResult вы должны написать этот блок If-else 2. Один для одного изображения, другой для нескольких изображений.

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

Самая важная часть, получить путь к изображению из 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();
    }
}

Надеюсь, это поможет тебе.

Хасиб Актер
источник
1

Я получил null из Cursor. Затем нашел решение преобразовать Uriв, Bitmapкоторое отлично работает.

Вот решение, которое мне подходит:

@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
источник
0

Привет, код ниже работает нормально.

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

Вы хотите больше разъяснений. http://mylearnandroid.blogspot.in/2014/02/multiple-choose-custom-gallery.html

Рамеш Тангарадж
источник
1
если работает - нормально. Хорошо указать на устаревший код, но пока вы используете его без каких-либо проблем, его можно использовать. Важно знать, почему он устарел, будь то проблемы с безопасностью, более новый код более эффективен и т. Д. Но поскольку приложения Android имеют прямую совместимость, устаревший код по-прежнему будет работать в будущем.
JStephen
0

У меня тоже была такая же проблема. Я также хотел, чтобы пользователи могли легко фотографировать, выбирая фотографии из галереи. Не удалось найти собственный способ сделать это, поэтому я решил создать проект с открытым исходным кодом. Это очень похоже на MultipleImagePick, но просто лучший способ его реализации.

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;
    }
}
Гил Хулио
источник
0

Попробуйте этот IntentChooser . Просто добавьте несколько строк кода, все остальное я сделал за вас.

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: как упоминалось в ответах выше, EXTRA_ALLOW_MULTIPLE доступен только для API> = 18. И некоторые приложения галереи не делают эту функцию доступной (Google Фото и Документы ( com.android.documentsui) работают.

Туан Чау
источник
Не разрешает мне выбирать несколько изображений, даже если они добавленыintent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
Scorpion