这是我的第一个 Android 应用程序,我使用相机预览和 FileOutputStream 将图片保存在我的 SD 卡上。在应用程序中,我想通过按一次按钮来制作单张图片或连续图片行。当我调用方法“手动跟踪”时,预览会冻结,我只能返回上一个屏幕。当我调用方法“串行跟踪”时,应用程序以 NPE 结尾。(碰巧我在崩溃一次后也无法在其他应用程序中使用我的相机;必须重新启动我的设备)
我在哪里失败?
package com.example.autoimageapp;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import android.annotation.SuppressLint;
import android.hardware.Camera;
import android.hardware.Camera.PictureCallback;
import android.hardware.Camera.ShutterCallback;
import android.os.Environment;
import android.util.Log;
public class PictureTaker {
private static final int MEDIA_TYPE_IMAGE = 1;
private static final int MEDIA_TYPE_VIDEO = 2;
private static final String TAG = "PictureTaker";
private int milliseconds;
private CameraPreview preview;
public Thread t;
// Called when shutter is opened
private ShutterCallback shutterCallback = new ShutterCallback() {
public void onShutter() {
Log.d(TAG, "onShutter'd");
}
};
// Handles data for raw picture
private PictureCallback rawCallback = new PictureCallback() {
public void onPictureTaken(byte[] data, Camera camera) {
Log.d(TAG, "onPictureTaken - raw");
}
};
// Handles picture data after picture was taken.
// Saves picture.
private PictureCallback jpegCallback = new PictureCallback() {
@Override
public void onPictureTaken(byte[] data, Camera camera) {
Log.d(TAG, "onPictureTaken - jpeg");
File pictureFile = getOutputMediaFile(MEDIA_TYPE_IMAGE);
if (pictureFile == null) {
Log.d(TAG,
"Error creating media file, check storage permissions.");
return;
}
try {
FileOutputStream fos = new FileOutputStream(pictureFile);
fos.write(data);
fos.close();
} catch (FileNotFoundException e) {
Log.d(TAG, "File not found: " + e.getMessage());
} catch (IOException e) {
Log.d(TAG, "Error accessing file: " + e.getMessage());
}
}
};
public PictureTaker(CameraPreview preview, int milliseconds) {
this.milliseconds = milliseconds;
this.preview = preview;
}
/** Create a File for saving an image or video */
@SuppressLint({ "NewApi", "SimpleDateFormat" })
private static File getOutputMediaFile(int type) {
if (Environment.getExternalStorageState().equals(
Environment.MEDIA_UNMOUNTED)) {
Log.d(TAG, "SD Card is not mounted");
return null;
}
// Create folder with name "AutoImageApp" in "Pictures"
File mediaStorageDir = new File(
Environment
.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),
"AutoImageApp");
// Create the storage directory if it does not exist
if (!mediaStorageDir.exists()) {
if (!mediaStorageDir.mkdirs()) {
Log.d("AutoImageApp", "failed to create directory");
return null;
}
}
// Create a media file name
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmssSSS")
.format(new Date());
File mediaFile;
if (type == MEDIA_TYPE_IMAGE) {
mediaFile = new File(mediaStorageDir.getPath() + File.separator
+ "IMG_" + timeStamp + ".jpg");
} else if (type == MEDIA_TYPE_VIDEO) {
mediaFile = new File(mediaStorageDir.getPath() + File.separator
+ "VID_" + timeStamp + ".mp4");
} else {
return null;
}
return mediaFile;
}
/**
* Calls
* {@link Camera#takePicture(ShutterCallback, PictureCallback, PictureCallback)}
* <br>
* with a frequency of milliseconds, which are given from the user in a
* Spinner.<br>
* Runs a new thread so the preview can be shown and pictures can be taken
* at the same time.
*/
public void takeSerialPics() {
t = new Thread() {
@Override
public void run() {
while (!isInterrupted()) {
Log.d(TAG, "vor takePicture Methode");
try {
preview.camera.takePicture(shutterCallback,
rawCallback, jpegCallback);
} catch (RuntimeException e) {
Log.d(TAG, "Smartphone zu lahm!");
return;
}
Log.d(TAG, "nach takePicture Methode");
try {
Thread.sleep(milliseconds);
} catch (InterruptedException e) {
interrupt();
}
}
}
};
t.start();
}
/**
* Calls
* {@link Camera#takePicture(ShutterCallback, PictureCallback, PictureCallback)}
* .
*/
public void takeSinglePics() {
preview.camera.takePicture(shutterCallback, rawCallback, jpegCallback);
}
}
我设置了权限:
<uses-feature android:name="android.hardware.camera" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
我认为 NPE 发生在第 57 行 -> fos.write(data)
这是堆栈跟踪:
02-20 14:53:26.689: D/PictureTaker(995): vor takePicture Methode
02-20 14:53:26.729: D/PictureTaker(995): nach takePicture Methode
02-20 14:53:26.769: D/PictureTaker(995): onShutter'd
02-20 14:53:27.229: D/PictureTaker(995): vor takePicture Methode
02-20 14:53:41.109: E/SensorManager(995): unregisterListener:: all sensors, listener = com.example.autoimageapp.Accelerometer@40569578
02-20 14:53:41.109: E/SensorManager(995): unregisterListener:: all sensors, listener = com.example.autoimageapp.MagneticField@4056bda8
02-20 14:53:41.109: E/SensorManager(995): unregisterListener:: all sensors, listener = com.example.autoimageapp.Gyroscope@4056cff0
02-20 14:54:26.789: D/SensorManager(1037): ====>>>>>Num Sensor: 1
02-20 14:54:26.789: D/SensorManager(1037): ====>>>>>Num Sensor: 2
02-20 14:54:26.789: D/SensorManager(1037): ====>>>>>Num Sensor: 3
02-20 14:54:26.789: D/SensorManager(1037): ====>>>>>Num Sensor: 4
02-20 14:54:26.799: D/SensorManager(1037): ====>>>>>Num Sensor: 5
02-20 14:54:26.799: D/SensorManager(1037): ====>>>>>Num Sensor: 6
02-20 14:54:26.799: D/SensorManager(1037): ====>>>>>Num Sensor: 0
02-20 14:54:26.799: E/SensorManager(1037): registerListener :: handle = 0 name= BMA220 delay= 200000 Listener= com.example.autoimageapp.Accelerometer@40568ed0
02-20 14:54:26.799: E/SensorManager(1037): =======>>>Sensor Thread RUNNING <<<========
02-20 14:54:26.799: E/SensorManager(1037): reg :: handle = 0
02-20 14:54:26.799: E/SensorManager(1037): registerListener :: handle = 1 name= MMC314X delay= 200000 Listener= com.example.autoimageapp.MagneticField@4056b700
02-20 14:54:26.799: E/SensorManager(1037): reg :: handle = 1
02-20 14:54:26.799: E/SensorManager(1037): registerListener :: handle = 0 name= BMA220 delay= 200000 Listener= com.example.autoimageapp.Accelerometer@40568ed0
02-20 14:54:26.809: E/SensorManager(1037): reg :: handle = 0
02-20 14:54:26.809: E/SensorManager(1037): registerListener :: handle = 1 name= MMC314X delay= 200000 Listener= com.example.autoimageapp.MagneticField@4056b700
02-20 14:54:26.809: E/SensorManager(1037): reg :: handle = 1
02-20 14:54:26.809: E/SensorManager(1037): registerListener :: handle = 0 name= BMA220 delay= 200000 Listener= com.example.autoimageapp.Accelerometer@40568ed0
02-20 14:54:26.819: E/SensorManager(1037): reg :: handle = 0
02-20 14:54:26.819: E/SensorManager(1037): registerListener :: handle = 1 name= MMC314X delay= 200000 Listener= com.example.autoimageapp.MagneticField@4056b700
02-20 14:54:26.819: E/SensorManager(1037): reg :: handle = 1
02-20 14:54:26.939: D/CameraPreview(1037): cannot open Camera
02-20 14:54:26.939: W/dalvikvm(1037): threadid=1: thread exiting with uncaught exception (group=0x40018578)
02-20 14:54:26.959: E/AndroidRuntime(1037): FATAL EXCEPTION: main
02-20 14:54:26.959: E/AndroidRuntime(1037): java.lang.NullPointerException
02-20 14:54:26.959: E/AndroidRuntime(1037): at com.example.autoimageapp.CameraPreview.surfaceCreated(CameraPreview.java:48)
02-20 14:54:26.959: E/AndroidRuntime(1037): at android.view.SurfaceView.updateWindow(SurfaceView.java:552)
02-20 14:54:26.959: E/AndroidRuntime(1037): at android.view.SurfaceView.dispatchDraw(SurfaceView.java:350)
02-20 14:54:26.959: E/AndroidRuntime(1037): at android.view.ViewGroup.drawChild(ViewGroup.java:1644)
02-20 14:54:26.959: E/AndroidRuntime(1037): at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1373)
02-20 14:54:26.959: E/AndroidRuntime(1037): at android.view.ViewGroup.drawChild(ViewGroup.java:1644)
02-20 14:54:26.959: E/AndroidRuntime(1037): at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1373)
02-20 14:54:26.959: E/AndroidRuntime(1037): at android.view.ViewGroup.drawChild(ViewGroup.java:1644)
02-20 14:54:26.959: E/AndroidRuntime(1037): at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1373)
02-20 14:54:26.959: E/AndroidRuntime(1037): at android.view.View.draw(View.java:6883)
02-20 14:54:26.959: E/AndroidRuntime(1037): at android.widget.FrameLayout.draw(FrameLayout.java:357)
02-20 14:54:26.959: E/AndroidRuntime(1037): at android.view.ViewGroup.drawChild(ViewGroup.java:1646)
02-20 14:54:26.959: E/AndroidRuntime(1037): at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1373)
02-20 14:54:26.959: E/AndroidRuntime(1037): at android.view.ViewGroup.drawChild(ViewGroup.java:1644)
02-20 14:54:26.959: E/AndroidRuntime(1037): at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1373)
02-20 14:54:26.959: E/AndroidRuntime(1037): at android.view.View.draw(View.java:6883)
02-20 14:54:26.959: E/AndroidRuntime(1037): at android.widget.FrameLayout.draw(FrameLayout.java:357)
02-20 14:54:26.959: E/AndroidRuntime(1037): at com.android.internal.policy.impl.PhoneWindow$DecorView.draw(PhoneWindow.java:1921)
02-20 14:54:26.959: E/AndroidRuntime(1037): at android.view.ViewRoot.draw(ViewRoot.java:1528)
02-20 14:54:26.959: E/AndroidRuntime(1037): at android.view.ViewRoot.performTraversals(ViewRoot.java:1264)
02-20 14:54:26.959: E/AndroidRuntime(1037): at android.view.ViewRoot.handleMessage(ViewRoot.java:1866)
02-20 14:54:26.959: E/AndroidRuntime(1037): at android.os.Handler.dispatchMessage(Handler.java:99)
02-20 14:54:26.959: E/AndroidRuntime(1037): at android.os.Looper.loop(Looper.java:130)
02-20 14:54:26.959: E/AndroidRuntime(1037): at android.app.ActivityThread.main(ActivityThread.java:3687)
02-20 14:54:26.959: E/AndroidRuntime(1037): at java.lang.reflect.Method.invokeNative(Native Method)
02-20 14:54:26.959: E/AndroidRuntime(1037): at java.lang.reflect.Method.invoke(Method.java:507)
02-20 14:54:26.959: E/AndroidRuntime(1037): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:867)
02-20 14:54:26.959: E/AndroidRuntime(1037): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:625)
02-20 14:54:26.959: E/AndroidRuntime(1037): at dalvik.system.NativeStart.main(Native Method)
这是我的班级“跟踪屏幕”的一部分,其中创建了“预览”:
preview = new CameraPreview(this);
((FrameLayout) findViewById(R.id.preview)).addView(preview);
preview.setKeepScreenOn(true);