web-dev-qa-db-fra.com

Caméra Android: l'intention de données renvoie null

J'ai une application Android qui contient plusieurs activités. 

Dans l'un d'eux, j'utilise un bouton qui appelle la caméra du périphérique:

public void onClick(View view) {
    Intent photoIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    startActivityForResult(photoIntent, IMAGE_CAPTURE);
}

Dans la même activité, j'appelle la méthode OnActivityResult pour le résultat de l'image:

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

Le problème est que l'intention data est null et que la méthode OnActivityResult passe directement au (resultCode == RESULT_CANCELED) et que l'application revient à l'activité précédente.

Comment puis-je résoudre ce problème et après avoir appelé l'appareil photo, l'application revient à l'activité actuelle qui contient une ImageView qui contiendra la photo prise?

Merci

117
soft_developer

L'application de caméra Android par défaut ne renvoie une intention non nulle que lors du renvoi d'une vignette dans l'intention renvoyée. Si vous transmettez EXTRA_OUTPUT avec un URI dans lequel écrire, il renverra une intention null et l'image sera dans l'URI que vous avez transmis.

Vous pouvez le vérifier en consultant le code source de l'application de la caméra sur GitHub:

J'imagine que vous passez soit d'une manière ou d'une autre à EXTRA_OUTPUT, soit que l'application de caméra sur votre téléphone fonctionne différemment.

196
Brian Slesinsky

J'ai trouvé une réponse facile. Ça marche!!

o

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 = crupAndScale(bitmap, 300); // if you mind scaling
                pofileImageView.setImageBitmap(bitmap);
            } catch (FileNotFoundException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

        }
    }

si vous souhaitez recadrer et redimensionner cette image 

public static  Bitmap crupAndScale (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;
}
13
izakos

Appareil photo de travail simple évitant le problème d'intention nulle

- tout le code modifié inclus dans cette réponse; près de tutoriel Android

J'ai passé beaucoup de temps sur cette question et j'ai donc décidé de créer un compte et de partager mes résultats avec vous.

Le didacticiel Android officiel "Prendre des photos simplement" s'est avéré ne pas tenir ce qu'il avait promis ... Le code fourni ne fonctionnait pas sur mon appareil: un Samsung Galaxy S4 Mini GT-I9195 fonctionnant sous Android version 4.4. 2/KitKat/API niveau 19. 

J'ai compris que le problème principal était la ligne suivante de la méthode invoquée lors de la capture de la photo (dispatchTakePictureIntent dans le tutoriel):

takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);

Cela a eu pour conséquence que l'intention capturée par onActivityResult a ensuite été nulle.

Pour résoudre ce problème, je me suis beaucoup inspiré des réponses précédentes ici et de quelques articles utiles sur github (principalement celui-ci de deepwinter - merci beaucoup à lui; vous voudrez peut-être consulter sa réponse sur un sujet étroitement lié post aussi bien).

Après ces conseils judicieux, j’ai opté pour la stratégie consistant à supprimer la ligne putExtra mentionnée et à récupérer l’image prise de la caméra dans la méthode onActivityResult () à la place de . Les lignes de code décisives pour récupérer les bitmap associés à l'image sont:

        Uri uri = intent.getData();
        Bitmap bitmap = null;
        try {
            bitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), uri);
        } catch (IOException e) {
            e.printStackTrace();
        }

J'ai créé une application exemplaire qui ne permet que de prendre une photo, de l'enregistrer sur la carte SD et de l'afficher. Je pense que cela pourrait être utile aux personnes qui se trouvent dans la même situation que moi lorsque je suis tombé sur cette question, car les suggestions d’aide actuelles se réfèrent principalement à des posts assez volumineux sur github qui font la chose en question mais ne sont pas trop faciles à superviser. pour les débutants comme moi ... En ce qui concerne le système de fichiers créé par défaut par Android Studio lors de la création d'un nouveau projet, il me suffisait de modifier trois fichiers à cette fin:

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>

Notez que la solution que j'ai trouvée au problème a également conduit à une simplification du fichier manifeste Android: les modifications suggérées par le tutoriel Android en termes d'ajout d'un fournisseur ne sont plus nécessaires car je n'utilise aucun de mes codes Java. Par conséquent, seules quelques lignes standard, concernant principalement les autorisations, ont dû être ajoutées au fichier manifeste.

De plus, il peut être intéressant de noter que l’importation automatique d’Android Studio peut ne pas être capable de gérer Java.text.SimpleDateFormat et Java.util.Date. Je devais importer les deux manuellement.

4
H.G.M.

Probablement parce que tu as eu quelque chose comme ça?

Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);                        
Uri fileUri =  CommonUtilities.getTBCameraOutputMediaFileUri();                  
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri);                        
startActivityForResult(takePictureIntent, 2);

Cependant, vous ne devez pas placer la sortie supplémentaire dans l'intention, car les données sont ensuite transférées dans l'URI au lieu de la variable de données. Pour cette raison, vous devez prendre les deux lignes au milieu, de sorte que vous avez

Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(takePictureIntent, 2);

C’est ce qui a causé le problème pour moi, espérons que cela a aidé.

2
Marius Hilarious

J'ai rencontré ce problème, la intent n'est pas nulle mais les informations envoyées via cette intent ne sont pas reçues dans onActionActivit()

 enter image description here

C'est une meilleure solution avec 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);

  }

la onActivityResult() récupère un bitmap stocké par 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í

Vérifiez mon exemple dans github:

https://github.com/Jorgesys/TakePicture

1
Elenasys

Le code Kotlin qui fonctionne pour moi:

 private fun takePhotoFromCamera() {
          val intent = Intent(Android.provider.MediaStore.ACTION_IMAGE_CAPTURE)
        startActivityForResult(intent, PERMISSIONS_REQUEST_TAKE_PICTURE_CAMERA)
      }

Et obtenir le résultat:

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

    }

}

et n'oubliez pas de déclarer le code de requête:

companion object {
 const val PERMISSIONS_REQUEST_TAKE_PICTURE_CAMERA = 300
  }
0
Hamed Jaliliani

Le code suivant fonctionne pour moi:

Intent cameraIntent = new Intent(Android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(cameraIntent, 2);

Et voici le résultat:

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();
        }
    }
}
0
Manitoba

Pour accéder à l'appareil photo, prendre des photos et définir ImageView sur Android 

Vous devez utiliser Uri file = Uri.fromFile(getOutputMediaFile()); pour Marshmallow.

Utilisez le lien ci-dessous pour obtenir le chemin

https://androidkennel.org/Android-camera-access-tutorial/

0
Ashwin H