Единственное намерение позволить пользователю сделать снимок ИЛИ выбрать изображение из галереи на Android

Я разрабатываю приложение для Android 2.1 вверх. Я хочу, чтобы мои пользователи могли выбрать изображение профиля в моем приложении (я не использую структуру контактов).

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

В настоящее время я могу сделать то или другое, но не оба.

Если я перейду непосредственно в режим камеры, используя MediaStore.ACTION_IMAGE_CAPTURE, тогда нет возможности попасть в галерею.

Если я перейду непосредственно к галерее с помощью Intent.ACTION_PICK, тогда я могу выбрать изображение, но если я нажму кнопку камеры (в правом верхнем углу галереи), то будет запущено новое намерение камеры. Таким образом, любая сделанная фотография не возвращается непосредственно в мое приложение. (Конечно, вы можете нажать кнопку "Назад", чтобы вернуться в галерею и выбрать изображение оттуда, но это лишний ненужный шаг и вовсе не интуитивно понятен).

Итак, есть ли способ объединить оба, или мне нужно предложить меню, чтобы сделать то или другое из моего приложения? Похоже, это было бы распространенным случаем... конечно, я что-то упустил?

Ответ 1

UPDATE. Другой ответ, используя EXTRA_INITIAL_INTENTS, является лучшим в этой точке. В то время, когда я написал свой ответ, EXTRA_INITIAL_INTENTS еще не существовал, поскольку он был добавлен в API Level 5.

Итак, есть способ объединить оба или я собираюсь предложить меню для делать то или другое изнутри моего приложение?

Напишите свою собственную галерею, в которой есть нужные функции.

Я бы подумал, что меню будет проще.

Похоже, это было бы обычным делом случай... конечно, я чего-то не хватает?

Разработчик рядом с вами подумает, что галерея должна позволить вам выбрать из местной галереи или же перепрыгнуть на Flickr, чтобы сделать выбор оттуда. Другой разработчик подумает, что камера должна не только позволять "делать снимок" через камеру, но и "делать снимок", выбирая что-то из галереи, переворачивая вещи так, как вы ее себе представляете. Еще один разработчик подумает, что галерея должна позволять выбирать из локальной галереи, или Flickr, или камеры, или веб-камеры, привязанной к сети. Еще один разработчик подумает, что галерея глупа, и пользователи должны просто выбирать файлы через проводник файлов. И так далее.

Все это в среде (мобильных телефонах), где флэш-память для ОС стоит на высоте.

Следовательно, IMHO, не совсем шокирует то, что основная команда Android решила предоставить строительные блоки для вас, чтобы собрать их, как вы сочтете нужным, вместо того, чтобы пытаться приспособить все возможные шаблоны.

Ответ 2

Вы можете попробовать сделать что-то вроде этого:

// ...
// Within your enclosing Class
// ...
private static final int SELECT_PICTURE = 1;

// ... 

Intent pickIntent = new Intent();
pickIntent.setType("image/*");
pickIntent.setAction(Intent.ACTION_GET_CONTENT);

Intent takePhotoIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);

String pickTitle = "Select or take a new Picture"; // Or get from strings.xml
Intent chooserIntent = Intent.createChooser(pickIntent, pickTitle);
chooserIntent.putExtra
(
  Intent.EXTRA_INITIAL_INTENTS, 
  new Intent[] { takePhotoIntent }
);

startActivityForResult(chooserIntent, SELECT_PICTURE);

Чтобы узнать, как справиться с результатом activitiy, обратитесь к этому вопросу


Примечание: критическая точка заключается в том, как определить, использовалась ли камера или галерея. Это показано в этом примере кода: fooobar.com/questions/41342/...

Ответ 3

В своей деятельности вы можете действовать следующим образом:

private static final int REQUEST_CODE_PICTURE= 1;

    /**
     * Click on View to change photo. Sets into View of your layout, android:onClick="clickOnPhoto"
     * @param view View
     */
    public void clickOnPhoto(View view) {
        Intent pickIntent = new Intent();
        pickIntent.setType("image/*");
        pickIntent.setAction(Intent.ACTION_GET_CONTENT);
        Intent takePhotoIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        String pickTitle = "Take or select a photo";
        Intent chooserIntent = Intent.createChooser(pickIntent, pickTitle);
        chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, new Intent[] { takePhotoIntent });
        startActivityForResult(chooserIntent, REQUEST_CODE_PICTURE);
    }

Затем добавьте всегда в свою активность метод onActivityResult:

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == REQUEST_CODE_PICTURE && resultCode == Activity.RESULT_OK) {
            if (data == null) {
                return;
            }
            try {
                InputStream inputStream = getContentResolver().openInputStream(data.getData());
                Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
                imgPhoto.setImageBitmap(bitmap);
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }
        }
    }

Ответ 4

Мой ответ почти идентичен решению @Macarse, но я также добавляю дополнительное намерение показывать приложения галереи (например, Google Photos) и написан на Kotlin:

val REQUEST_CODE_GET_IMAGE = 101

private fun addProfileImage() {
    val pickImageFileIntent = Intent()
    pickImageFileIntent.type = "image/*"
    pickImageFileIntent.action = Intent.ACTION_GET_CONTENT

    val pickGalleryImageIntent = Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI)

    val captureCameraImageIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)

    val pickTitle = "Capture from camera or Select from gallery the Profile photo"
    val chooserIntent = Intent.createChooser(pickImageFileIntent, pickTitle)
    chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, arrayOf(captureCameraImageIntent, pickGalleryImageIntent))
    startActivityForResult(chooserIntent, REQUEST_CODE_GET_IMAGE)
}

Извлечь изображение из результата намерения:

private var imageTempFile: File? = null
private var imageMimeType: String? = null

private fun extractImage(intent: Intent?) {
    val imageUri = intent?.data
    imageUri?.let {
        Glide.with(this)
                .load(imageUri)
                .into(profileImageCiv)
        imageTempFile = MediaUtils.copyContentFromUriToCacheFile(this, imageUri, Settings.DIRECTORY_CACHE_TEMP_PROFILE_IMAGE)
        imageMimeType = MediaUtils.getMimeType(this, imageUri)
    } ?: run {
        intent?.extras?.get("data")?.let { bitmap ->    // Bitmap was returned as raw bitmap
            Glide.with(this)
                    .load(bitmap)
                    .into(profileImageCiv)
            imageTempFile = MediaUtils.writeBitmapToCacheFile(this, bitmap as Bitmap, Settings.DIRECTORY_CACHE_TEMP_PROFILE_IMAGE)
            imageMimeType = "image/jpeg"    // The bitmap was compressed as JPEG format. The bitmap itself doesn't have any format associated to it
        } ?: run {
            imageTempFile = null
            imageMimeType = null
            Log.e("Intent data is null.")
            Log.d("Error during photo selection")
        }
    }
}