Android-камера: намерение данных возвращает null
У меня есть приложение для Android, которое содержит несколько действий.
В одном из них я использую кнопку, которая вызовет камеру устройства:
public void onClick(View view) {
Intent photoIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(photoIntent, IMAGE_CAPTURE);
}
В той же активности я вызываю метод OnActivityResult
для результата изображения:
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == IMAGE_CAPTURE) {
if (resultCode == RESULT_OK) {
Bitmap image = (Bitmap) data.getExtras().get("data");
ImageView imageview = (ImageView) findViewById(R.id.pic);
imageview.setImageBitmap(image);
} else if (resultCode == RESULT_CANCELED) {
Toast.makeText(this, "CANCELED ", Toast.LENGTH_LONG).show();
}
}
}
Проблема заключается в том, что цель data
равна нулю, а метод OnActivityResult
обращается непосредственно к (resultCode == RESULT_CANCELED)
, и приложение возвращается к предыдущему уровню.
Как я могу исправить эту проблему и после вызова камеры приложение вернется к текущей активности, которая содержит ImageView
, которая будет содержать сделанный снимок?
Спасибо
Ответы
Ответ 1
Приложение камеры Android по умолчанию возвращает ненулевое намерение только при передаче эскиза в возвращаемом намерении. Если вы передадите EXTRA_OUTPUT
с URI для записи, он вернет намерение null
и изображение будет в URI, который вы передали.
Вы можете проверить это, посмотрев исходный код приложения камеры на GitHub:
Я бы предположил, что вы либо каким-то образом проходите в EXTRA_OUTPUT
, либо приложение камеры на вашем телефоне работает по-другому.
Ответ 2
Я нашел простой ответ. это работает !!
private void openCameraForResult(int requestCode){
Intent photo = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
Uri uri = Uri.parse("file:///sdcard/photo.jpg");
photo.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, uri);
startActivityForResult(photo,requestCode);
}
if (requestCode == CAMERA_REQUEST_CODE) {
if (resultCode == Activity.RESULT_OK) {
File file = new File(Environment.getExternalStorageDirectory().getPath(), "photo.jpg");
Uri uri = Uri.fromFile(file);
Bitmap bitmap;
try {
bitmap = MediaStore.Images.Media.getBitmap(getContentResolver(), uri);
bitmap = cropAndScale(bitmap, 300); // if you mind scaling
profileImageView.setImageBitmap(bitmap);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
если вы хотите обрезать и масштабировать это изображение
public static Bitmap cropAndScale (Bitmap source, int scale){
int factor = source.getHeight() <= source.getWidth() ? source.getHeight(): source.getWidth();
int longer = source.getHeight() >= source.getWidth() ? source.getHeight(): source.getWidth();
int x = source.getHeight() >= source.getWidth() ?0:(longer-factor)/2;
int y = source.getHeight() <= source.getWidth() ?0:(longer-factor)/2;
source = Bitmap.createBitmap(source, x, y, factor, factor);
source = Bitmap.createScaledBitmap(source, scale, scale, false);
return source;
}
Ответ 3
Простая рабочая камера, избегающая проблемы с нулевым намерением
- все измененные коды включены в этот ответ; рядом с учебником по андроиде
Я потратил много времени на эту проблему, поэтому решил создать учетную запись и поделиться с вами своими результатами.
Официальное учебное пособие по андроиде "Взятие фотографий просто" оказалось не совсем тем, что обещало.
Приведенный здесь код не работал на моем устройстве: Samsung Galaxy S4 Mini GT-I9195 работает под управлением Android версии 4.4.2/KitKat/API уровня 19.
Я понял, что основной проблемой была следующая строка в методе, вызванном при захвате фотографии (dispatchTakePictureIntent
в учебнике):
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);
Это привело к тому, что намерение впоследствии было уловлено onActivityResult
равным нулю.
Чтобы решить эту проблему, я извлек много вдохновения из более ранних ответов здесь и некоторых полезных сообщений о github (в основном этот по глубине - большое спасибо ему, возможно, вы захотите проверить его ответ на тесно связанную статью).
Следуя этим приятным советам, я выбрал стратегию удаления упомянутой строки putExtra
и выполнил соответствующую задачу возврата назад сделанной фотографии из камеры в методе onActivityResult().
Решающими линиями кода для возврата растрового изображения, связанного с изображением, являются:
Uri uri = intent.getData();
Bitmap bitmap = null;
try {
bitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), uri);
} catch (IOException e) {
e.printStackTrace();
}
Я создал примерное приложение, которое просто имеет возможность сделать снимок, сохранить его на SD-карте и отобразить на нем.
Я думаю, что это может быть полезно для людей в той же ситуации, что и я, когда я наткнулся на эту проблему, поскольку текущие справочные предложения в основном касаются довольно обширных сообщений github, которые делают эту вещь, но не слишком легко контролировать таких новичков, как меня.
Что касается файловой системы Android Studio создает по умолчанию при создании нового проекта, мне просто нужно было изменить три файла для моей цели:
activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.example.android.simpleworkingcameraapp.MainActivity">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="takePicAndDisplayIt"
android:text="Take a pic and display it." />
<ImageView
android:id="@+id/image1"
android:layout_width="match_parent"
android:layout_height="200dp" />
</LinearLayout>
MainActivity.java:
package com.example.android.simpleworkingcameraapp;
import android.content.Intent;
import android.graphics.Bitmap;
import android.media.Image;
import android.net.Uri;
import android.os.Environment;
import android.provider.MediaStore;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;
import android.widget.Toast;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class MainActivity extends AppCompatActivity {
private ImageView image;
static final int REQUEST_TAKE_PHOTO = 1;
String mCurrentPhotoPath;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
image = (ImageView) findViewById(R.id.image1);
}
// copied from the android development pages; just added a Toast to show the storage location
private File createImageFile() throws IOException {
// Create an image file name
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmm").format(new Date());
String imageFileName = "JPEG_" + timeStamp + "_";
File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES);
File image = File.createTempFile(
imageFileName, /* prefix */
".jpg", /* suffix */
storageDir /* directory */
);
// Save a file: path for use with ACTION_VIEW intents
mCurrentPhotoPath = image.getAbsolutePath();
Toast.makeText(this, mCurrentPhotoPath, Toast.LENGTH_LONG).show();
return image;
}
public void takePicAndDisplayIt(View view) {
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if (intent.resolveActivity(getPackageManager()) != null) {
File file = null;
try {
file = createImageFile();
} catch (IOException ex) {
// Error occurred while creating the File
}
startActivityForResult(intent, REQUEST_TAKE_PHOTO);
}
}
@Override
protected void onActivityResult(int requestCode, int resultcode, Intent intent) {
if (requestCode == REQUEST_TAKE_PHOTO && resultcode == RESULT_OK) {
Uri uri = intent.getData();
Bitmap bitmap = null;
try {
bitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), uri);
} catch (IOException e) {
e.printStackTrace();
}
image.setImageBitmap(bitmap);
}
}
}
AndroidManifest.xml:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.android.simpleworkingcameraapp">
<!--only added paragraph-->
<uses-feature
android:name="android.hardware.camera"
android:required="true" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <!-- only crucial line to add; for me it still worked without the other lines in this paragraph -->
<uses-permission android:name="android.permission.CAMERA" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Обратите внимание, что решение, которое я нашел для проблемы, также привело к упрощению файла манифеста android: изменения, предлагаемые учебным пособием android с точки зрения добавления провайдера, больше не нужны, так как я не использую никаких в моем java-код. Следовательно, в файл манифеста нужно было добавить лишь несколько стандартных строк - почти относительно разрешений.
Кроме того, было бы полезно указать, что Android-аудит не может обрабатывать java.text.SimpleDateFormat
и java.util.Date
. Мне пришлось импортировать оба из них вручную.
Ответ 4
Возможно, потому, что у вас было что-то вроде этого?
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
Uri fileUri = CommonUtilities.getTBCameraOutputMediaFileUri();
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri);
startActivityForResult(takePictureIntent, 2);
Однако вы не должны помещать дополнительный вывод в намерение, потому что тогда данные переходят в URI вместо переменной данных. По этой причине вам нужно взять две строки в середине, так что вы
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(takePictureIntent, 2);
Вот что вызвало эту проблему для меня, надеюсь, что это помогло.
Ответ 5
У меня возникла эта проблема, intent
не является нулевым, но информация, отправленная через этот intent
, не получена в onActionActivit()
![enter image description here]()
Это лучшее решение с использованием getContentResolver() :
private Uri imageUri;
private ImageView myImageView;
private Bitmap thumbnail;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
...
...
...
myImageview = (ImageView) findViewById(R.id.pic);
values = new ContentValues();
values.put(MediaStore.Images.Media.TITLE, "MyPicture");
values.put(MediaStore.Images.Media.DESCRIPTION, "Photo taken on " + System.currentTimeMillis());
imageUri = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
startActivityForResult(intent, PICTURE_RESULT);
}
onActivityResult()
получает растровое изображение, хранящееся в getContentResolver() :
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_CODE_TAKE_PHOTO && resultCode == RESULT_OK) {
Bitmap bitmap;
try {
bitmap = MediaStore.Images.Media.getBitmap(getContentResolver(), imageUri);
myImageView.setImageBitmap(bitmap);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
![introducir la descripción de la imagen aquí]()
Проверьте мой пример в github:
https://github.com/Jorgesys/TakePicture
Ответ 6
Следующий код работает для меня:
Intent cameraIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(cameraIntent, 2);
И вот результат:
protected void onActivityResult(int requestCode, int resultCode, Intent imageReturnedIntent)
{
super.onActivityResult(requestCode, resultCode, imageReturnedIntent);
if(resultCode == RESULT_OK)
{
Uri selectedImage = imageReturnedIntent.getData();
ImageView photo = (ImageView) findViewById(R.id.add_contact_label_photo);
Bitmap mBitmap = null;
try
{
mBitmap = Media.getBitmap(this.getContentResolver(), selectedImage);
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
Ответ 7
Вы передаете код действия для записи видео, но обрабатываете результат как фотографию.
Ответ 8
Чтобы получить доступ к камере и сделать снимки и установить ImageView на Android
Вы должны использовать Uri file = Uri.fromFile(getOutputMediaFile());
для зефира.
Используйте ссылку ниже, чтобы получить путь
https://androidkennel.org/android-camera-access-tutorial/
Ответ 9
Код Котлин, который работает для меня:
private fun takePhotoFromCamera() {
val intent = Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE)
startActivityForResult(intent, PERMISSIONS_REQUEST_TAKE_PICTURE_CAMERA)
}
и получите результат:
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == PERMISSIONS_REQUEST_TAKE_PICTURE_CAMERA) {
if (resultCode == Activity.RESULT_OK) {
val photo: Bitmap? = MediaStore.Images.Media.getBitmap(this.contentResolver, Uri.parse( data!!.dataString) )
// Do something here : set image to an ImageView or save it ..
imgV_pic.imageBitmap = photo
} else if (resultCode == Activity.RESULT_CANCELED) {
Log.i(TAG, "Camera , RESULT_CANCELED ")
}
}
}
и не забудьте объявить код запроса:
companion object {
const val PERMISSIONS_REQUEST_TAKE_PICTURE_CAMERA = 300
}
Ответ 10
После долгих попыток учиться я смог в этом разобраться. Во-первых, переменные из Intent всегда будут нулевыми, поэтому проверка на !null
приведет к сбою приложения, если вы передаете URI startActivityForResult. Следуйте приведенному ниже примеру.
Я буду использовать Kotlin.
Откройте намерение камеры
fun addBathroomPhoto(){
addbathroomphoto.setOnClickListener{
request_capture_image=2
var takePictureIntent:Intent?
takePictureIntent =Intent(MediaStore.ACTION_IMAGE_CAPTURE)
if(takePictureIntent.resolveActivity(activity?.getPackageManager()) != null){
val photoFile: File? = try {
createImageFile()
} catch (ex: IOException) {
// Error occurred while creating the File
null
}
if (photoFile != null) {
val photoURI: Uri = FileProvider.getUriForFile(
activity!!,
"ogavenue.ng.hotelroomkeeping.fileprovider",photoFile)
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT,
photoURI);
startActivityForResult(takePictureIntent,
request_capture_image);
}
}
}
} '
Создайте createImageFile(). Но вы ДОЛЖНЫ сделать переменную imageFilePath глобальной. Пример того, как его создать, приведен в официальной документации Android и довольно прост:
Получить намерение
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (requestCode == 1 && resultCode == RESULT_OK) {
add_room_photo_txt.text=""
var myBitmap=BitmapFactory.decodeFile(imageFilePath)
addroomphoto.setImageBitmap(myBitmap)
var file=File(imageFilePath)
var fis=FileInputStream(file)
var bm = BitmapFactory.decodeStream(fis);
roomphoto=getBytesFromBitmap(bm) }}
Метод getBytesFromBitmap
fun getBytesFromBitmap(bitmap:Bitmap):ByteArray{
var stream=ByteArrayOutputStream()
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, stream);
return stream.toByteArray();
}
Надеюсь, это поможет.
Ответ 11
Когда мы снимаем изображение с камеры в Android, то Uri
или data.getdata()
становятся нулевыми. У нас есть два решения для решения этой проблемы.
- Получить путь Uri из растрового изображения
- Получить путь Uri от курсора.
Это как извлечь Uri из растрового изображения. Сначала захватите изображение через Intent, которое будет одинаковым для обоих методов:
// Capture Image
captureImg.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if (intent.resolveActivity(getPackageManager()) != null) {
startActivityForResult(intent, reqcode);
}
}
});
Теперь реализуем OnActivityResult
, который будет одинаковым для обоих методов:
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(requestCode==reqcode && resultCode==RESULT_OK)
{
Bitmap photo = (Bitmap) data.getExtras().get("data");
ImageView.setImageBitmap(photo);
// CALL THIS METHOD TO GET THE URI FROM THE BITMAP
Uri tempUri = getImageUri(getApplicationContext(), photo);
// Show Uri path based on Image
Toast.makeText(LiveImage.this,"Here "+ tempUri, Toast.LENGTH_LONG).show();
// Show Uri path based on Cursor Content Resolver
Toast.makeText(this, "Real path for URI : "+getRealPathFromURI(tempUri), Toast.LENGTH_SHORT).show();
}
else
{
Toast.makeText(this, "Failed To Capture Image", Toast.LENGTH_SHORT).show();
}
}
Теперь создайте все вышеперечисленные методы для создания Uri из методов Image и Cursor:
Путь Uri из растрового изображения:
private Uri getImageUri(Context applicationContext, Bitmap photo) {
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
photo.compress(Bitmap.CompressFormat.JPEG, 100, bytes);
String path = MediaStore.Images.Media.insertImage(LiveImage.this.getContentResolver(), photo, "Title", null);
return Uri.parse(path);
}
Uri из реального пути сохраненного изображения:
public String getRealPathFromURI(Uri uri) {
Cursor cursor = getContentResolver().query(uri, null, null, null, null);
cursor.moveToFirst();
int idx = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA);
return cursor.getString(idx);
}