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í 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.

  1. Откройте намерение камеры

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

    } '

  2. Создайте createImageFile(). Но вы ДОЛЖНЫ сделать переменную imageFilePath глобальной. Пример того, как его создать, приведен в официальной документации Android и довольно прост:

  3. Получить намерение

     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) }}
    
  4. Метод getBytesFromBitmap

      fun getBytesFromBitmap(bitmap:Bitmap):ByteArray{
    
      var stream=ByteArrayOutputStream()
      bitmap.compress(Bitmap.CompressFormat.JPEG, 100, stream);
      return stream.toByteArray();
      }
    

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

Ответ 11

Когда мы снимаем изображение с камеры в Android, то Uri или data.getdata() становятся нулевыми. У нас есть два решения для решения этой проблемы.

  1. Получить путь Uri из растрового изображения
  2. Получить путь 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);
}