Application de caméra de travail simple évitant le problème d'intention nulle
- tous les codes modifiés inclus dans cette réponse; proche du tutoriel android
J'ai passé beaucoup de temps sur ce problème, 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 tout à fait ce qu'il avait promis. Le code qui y est fourni ne fonctionnait pas sur mon appareil: un Samsung Galaxy S4 Mini GT-I9195 exécutant la version Android 4.4.2 / KitKat / API Level 19.
J'ai compris que le problème principal était la ligne suivante dans la méthode invoquée lors de la capture de la photo ( dispatchTakePictureIntent
dans le tutoriel):
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);
Il en a résulté que l'intention a été rattrapée par la suite en onActivityResult
étant nulle.
Pour résoudre ce problème, j'ai tiré beaucoup d' inspiration sur les réponses précédentes ici et quelques messages utiles sur GitHub ( la plupart du temps cette un par deepwinter - grand merci à lui, vous pourriez vouloir vérifier sa réponse sur un étroitement lié après aussi).
Suite à ces conseils agréables, j'ai choisi la stratégie de suppression de la putExtra
ligne mentionnée et de faire la chose correspondante de récupérer la photo prise de la caméra dans la méthode onActivityResult () à la place. Les lignes de code décisives pour récupérer le bitmap associé à 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 a simplement la capacité de prendre une photo, de la sauvegarder sur la carte SD et de l'afficher. Je pense que cela pourrait être utile pour les personnes dans la même situation que moi lorsque je suis tombé sur ce problème, car les suggestions d'aide actuelles se réfèrent principalement à des publications github assez volumineuses 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 qu'Android Studio crée par défaut lors de la création d'un nouveau projet, j'ai juste eu à changer trois fichiers pour mon objectif:
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 pour le problème a également conduit à une simplification du fichier manifeste android: les changements suggérés par le tutoriel android en termes d'ajout d'un fournisseur ne sont plus nécessaires puisque je n'en utilise aucun dans mon code java. Par conséquent, seules quelques lignes standard - concernant principalement les autorisations - ont dû être ajoutées au fichier manifeste.
Il peut également être utile de souligner que l'importation automatique d'Android Studio peut ne pas être capable de gérer java.text.SimpleDateFormat
et java.util.Date
. J'ai dû les importer tous les deux manuellement.