我实现了一个相当标准的预览和按钮,用于简单的拍照,表面按预期工作,即使我的笔记本电脑的网络摄像头连接了一个模拟器。应始终在onPictureTaken()运行之前启动预览,这样看起来似乎不是问题。
package com.davepeyton.android.seekbromance;
/**
* Created by Dave on 6/5/2016.
*/
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.hardware.Camera;
import android.hardware.Camera.Size;
import android.view.LayoutInflater;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.ViewGroup;
import android.util.Log;
import android.widget.Button;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;
import java.util.UUID;
public class BrofileCameraFragment extends Fragment {
private static final String TAG = "BrofileCameraFragment";
public static final String EXTRA_PHOTO_FILENAME = "com.davepeyton.android.seekbromance.photo_filename";
private Camera mCamera;
private SurfaceView mSurfaceView;
private View mProgressContainer;
private Camera.ShutterCallback mShutterCallback = new Camera.ShutterCallback() {
public void onShutter() {
// Display the progress indicator
mProgressContainer.setVisibility( View.VISIBLE);
}
};
private Camera.PictureCallback mJpegCallback = new Camera.PictureCallback() {
public void onPictureTaken(byte[] data, Camera camera) {
// Create a filename
String filename = UUID.randomUUID().toString() + ". jpg";
// Save the jpeg data to disk
FileOutputStream os = null;
boolean success = true;
try {
os = getActivity().openFileOutput(filename, Context.MODE_PRIVATE);
os.write(data);
} catch (Exception e) {
Log.e(TAG, "Error writing to file " + filename, e);
success = false;
} finally {
try {
if (os != null)
os.close();
} catch (Exception e) {
Log.e(TAG, "Error closing file " + filename, e);
success = false;
}
}
if (success) {
Log.i(TAG, "JPEG saved at " + filename);
// Pass the filename to BrofileSelfiePreviewFragment
Intent i = new Intent();
i.putExtra(EXTRA_PHOTO_FILENAME, filename);
getActivity().setResult(Activity.RESULT_OK, i);
} else {
getActivity().setResult(Activity.RESULT_CANCELED);
}
getActivity().finish();
}
};
/** A simple algorithm to get the largest size available. For a more robust version, see
* CameraPreview.java in the ApiDemos sample app from Android. */
private Size getBestSupportedSize(List <Camera.Size> sizes, int width, int height) {
Size bestSize = sizes.get( 0);
int largestArea = bestSize.width * bestSize.height;
for (Size s : sizes) {
int area = s.width * s.height;
if (area > largestArea) {
bestSize = s; largestArea = area;
}
}
return bestSize;
}
@Override
@SuppressWarnings("deprecation")
public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.brofile_camera, parent, false);
mProgressContainer = v.findViewById(R.id.brofile_camera_progressContainer);
mProgressContainer.setVisibility(View.INVISIBLE);
Button takePictureButton = (Button)v.findViewById(R.id.brofile_camera_takePictureButton);
takePictureButton.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v) {
if (mCamera != null) {
mCamera.takePicture(mShutterCallback, null, null, mJpegCallback);
}
}
});
mSurfaceView = (SurfaceView)v.findViewById(R.id.brofile_camera_surfaceView);
SurfaceHolder holder = mSurfaceView.getHolder();
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
// Note that setType() and SURFACE_TYPE_PUSH_BUFFERS are both deprecated.
// However, they are needed for the Camera view to work on pre-3.0 devices.
holder.addCallback( new SurfaceHolder.Callback() {
// A callback is required to coordinate the Surface's life cycle with the camera's preview.
public void surfaceCreated( SurfaceHolder holder) {
// Tells the camera to use this surface as its preview area
try { if (mCamera != null) {
mCamera.setPreviewDisplay( holder);
}
} catch (IOException exception) {
Log.e( TAG, "Error setting up preview display", exception);
}
}
public void surfaceDestroyed( SurfaceHolder holder) {
// We can no longer display on this surface, so stop the preview.
if (mCamera != null) {
mCamera.stopPreview();
}
}
public void surfaceChanged( SurfaceHolder holder, int format, int w, int h) {
if (mCamera == null) return;
// The surface has changed size; update the camera preview size
Camera.Parameters parameters = mCamera.getParameters();
Size s = getBestSupportedSize(parameters.getSupportedPreviewSizes(), w, h);
parameters.setPreviewSize( s.width, s.height);
s = getBestSupportedSize(parameters.getSupportedPictureSizes(), w, h);
parameters.setPictureSize(s.width, s.height);
mCamera.setParameters( parameters);
try {
mCamera.startPreview();
} catch (Exception e) {
Log.e( TAG, "Could not start preview", e);
mCamera.release();
mCamera = null; }
} });
return v;
}
@TargetApi(9)
@Override
public void onResume() {
super.onResume();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
mCamera = Camera.open(0);
} else {
mCamera = Camera.open();
}
}
@Override
public void onPause() {
super.onPause();
if (mCamera != null) {
mCamera.release();
mCamera = null;
}
}
}
这是logcat。图像似乎没有保存任何文件。
08-15 13:51:27.364: V/EmulatedCamera_QemuDevice(1140): startDevice: Qemu camera device 'AndroidEmulatorVC0' is started for NV21[640x480] frames
08-15 13:51:27.364: V/EmulatedCamera_Device(1140): startDeliveringFrames
08-15 13:51:27.364: V/EmulatedCamera_Device(1140): startWorkerThread
08-15 13:51:27.365: D/AndroidRuntime(2738): Shutting down VM
08-15 13:51:27.365: D/AndroidRuntime(2738): --------- beginning of crash
08-15 13:51:27.365: E/AndroidRuntime(2738): FATAL EXCEPTION: main
08-15 13:51:27.365: E/AndroidRuntime(2738): Process: com.davepeyton.android.seekbromance, PID: 2738
08-15 13:51:27.365: E/AndroidRuntime(2738): java.lang.RuntimeException: takePicture failed
08-15 13:51:27.365: E/AndroidRuntime(2738): at android.hardware.Camera.native_takePicture(Native Method)
08-15 13:51:27.365: E/AndroidRuntime(2738): at android.hardware.Camera.takePicture(Camera.java:1436)
08-15 13:51:27.365: E/AndroidRuntime(2738): at com.davepeyton.android.seekbromance.BrofileCameraFragment$3.onClick(BrofileCameraFragment.java:106)
08-15 13:51:27.365: E/AndroidRuntime(2738): at android.view.View.performClick(View.java:4780)
08-15 13:51:27.365: E/AndroidRuntime(2738): at android.view.View$PerformClick.run(View.java:19866)
08-15 13:51:27.365: E/AndroidRuntime(2738): at android.os.Handler.handleCallback(Handler.java:739)
08-15 13:51:27.365: E/AndroidRuntime(2738): at android.os.Handler.dispatchMessage(Handler.java:95)
08-15 13:51:27.365: E/AndroidRuntime(2738): at android.os.Looper.loop(Looper.java:135)
08-15 13:51:27.365: E/AndroidRuntime(2738): at android.app.ActivityThread.main(ActivityThread.java:5254)
08-15 13:51:27.365: E/AndroidRuntime(2738): at java.lang.reflect.Method.invoke(Native Method)
08-15 13:51:27.365: E/AndroidRuntime(2738): at java.lang.reflect.Method.invoke(Method.java:372)
08-15 13:51:27.365: E/AndroidRuntime(2738): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903)
08-15 13:51:27.365: E/AndroidRuntime(2738): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)
08-15 13:51:27.366: V/EmulatedCamera_Device(1140): Starting emulated camera device worker thread...
08-15 13:51:27.366: V/EmulatedCamera_Device(1140): Emulated device's worker thread has been started.
答案 0 :(得分:0)
由于takePicture是异步的,因此mJpegCallback
内的活动内务管理可能存在问题。
当这些陈述移至onPause()
时,转换按预期工作。当然,检查新照片是否存在以确保当前活动实际被销毁。拍摄成功照片后的目的是什么。