Einfache funktionierende Kamera-App, die das Null-Intent-Problem vermeidet
- alle geänderten Codes, die in dieser Antwort enthalten sind; in der Nähe von Android Tutorial
Ich habe viel Zeit mit diesem Thema verbracht, daher habe ich beschlossen, ein Konto zu erstellen und meine Ergebnisse mit Ihnen zu teilen.
Das offizielle Android-Tutorial "Taking Photos Simply" hat nicht ganz das gehalten, was es versprochen hatte. Der dort bereitgestellte Code funktionierte auf meinem Gerät nicht: ein Samsung Galaxy S4 Mini GT-I9195 mit Android Version 4.4.2 / KitKat / API Level 19.
Ich fand heraus, dass das Hauptproblem die folgende Zeile in der Methode war, die beim Aufnehmen des Fotos aufgerufen wurde ( dispatchTakePictureIntent
im Tutorial):
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);
Dies führte dazu onActivityResult
, dass die Absicht später durch Null erfasst wurde .
Um dieses Problem zu lösen, habe ich mich von früheren Antworten hier und einigen hilfreichen Beiträgen zu Github inspirieren lassen (meistens von Deepwinter - ein großes Dankeschön an ihn; vielleicht möchten Sie auch seine Antwort auf einen eng verwandten Beitrag lesen ).
Nach diesen angenehmen Ratschlägen entschied ich mich für die Strategie, die erwähnte putExtra
Zeile zu löschen und stattdessen das aufgenommene Bild von der Kamera innerhalb der onActivityResult () -Methode zurückzugewinnen. Die entscheidenden Codezeilen, um die dem Bild zugeordnete Bitmap wiederherzustellen, sind:
Uri uri = intent.getData();
Bitmap bitmap = null;
try {
bitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), uri);
} catch (IOException e) {
e.printStackTrace();
}
Ich habe eine beispielhafte App erstellt, mit der Sie einfach ein Bild aufnehmen, auf der SD-Karte speichern und anzeigen können. Ich denke, dies könnte für Leute in der gleichen Situation wie ich hilfreich sein, als ich über dieses Problem gestolpert bin, da sich die aktuellen Hilfevorschläge meist auf ziemlich umfangreiche Github-Posts beziehen, die die fragliche Sache tun, aber für Neulinge wie nicht allzu leicht zu überwachen sind mich. In Bezug auf das Dateisystem, das Android Studio beim Erstellen eines neuen Projekts standardmäßig erstellt, musste ich nur drei Dateien für meinen Zweck ändern:
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>
Beachten Sie, dass die Lösung, die ich für das Problem gefunden habe, auch zu einer Vereinfachung der Android-Manifest-Datei geführt hat: Die im Android-Tutorial vorgeschlagenen Änderungen zum Hinzufügen eines Anbieters werden nicht mehr benötigt, da ich in meinem Java-Code keine mehr verwende. Daher mussten der Manifestdatei nur wenige Standardzeilen hinzugefügt werden - hauptsächlich in Bezug auf Berechtigungen.
Es kann außerdem hilfreich sein, darauf hinzuweisen, dass der Autoimport von Android Studio möglicherweise nicht in der Lage ist, java.text.SimpleDateFormat
und zu verarbeiten java.util.Date
. Ich musste beide manuell importieren.