(ブレークなしで)キャプチャボタンを連続してクリックすると、ランタイム例外が発生し、この問題を解決するにはどうすればよいですか?
それが不可能な場合、この例外をどのように処理できますか?
btnCapture = (ImageButton) findViewById(R.id.btnCapture);
final MediaPlayer mp = MediaPlayer.create(CameraLauncherActivity.this, R.raw.button);
btnCapture.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// line where getting RuntimeException
camera.takePicture(null, null, mPicture);
}
});
ログ:
02-12 14:48:41.580: E/AndroidRuntime(6997): FATAL EXCEPTION: main
02-12 14:48:41.580: E/AndroidRuntime(6997): Java.lang.RuntimeException: takePicture failed
02-12 14:48:41.580: E/AndroidRuntime(6997): at Android.hardware.Camera.native_takePicture(Native Method)
02-12 14:48:41.580: E/AndroidRuntime(6997): at Android.hardware.Camera.takePicture(Camera.Java:1126)
02-12 14:48:41.580: E/AndroidRuntime(6997): at Android.hardware.Camera.takePicture(Camera.Java:1071)
02-12 14:48:41.580: E/AndroidRuntime(6997): at app.cam.shane.CameraLauncherActivity$3.onClick(CameraLauncherActivity.Java:116)
02-12 14:48:41.580: E/AndroidRuntime(6997): at Android.view.View.performClick(View.Java:4223)
02-12 14:48:41.580: E/AndroidRuntime(6997): at Android.view.View$PerformClick.run(View.Java:17275)
02-12 14:48:41.580: E/AndroidRuntime(6997): at Android.os.Handler.handleCallback(Handler.Java:615)
02-12 14:48:41.580: E/AndroidRuntime(6997): at Android.os.Handler.dispatchMessage(Handler.Java:92)
02-12 14:48:41.580: E/AndroidRuntime(6997): at Android.os.Looper.loop(Looper.Java:137)
02-12 14:48:41.580: E/AndroidRuntime(6997): at Android.app.ActivityThread.main(ActivityThread.Java:4921)
02-12 14:48:41.580: E/AndroidRuntime(6997): at Java.lang.reflect.Method.invokeNative(Native Method)
02-12 14:48:41.580: E/AndroidRuntime(6997): at Java.lang.reflect.Method.invoke(Method.Java:511)
02-12 14:48:41.580: E/AndroidRuntime(6997): at com.Android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.Java:1036)
02-12 14:48:41.580: E/AndroidRuntime(6997): at com.Android.internal.os.ZygoteInit.main(ZygoteInit.Java:803)
02-12 14:48:41.580: E/AndroidRuntime(6997): at dalvik.system.NativeStart.main(Native Method)
注:-Pudding Cameraと同様に、キャプチャボタンを連続してタップできますが、50回クリックすると10をキャプチャするか、例外を表示しません。より多くの画像、特定の時間の後の各画像、例外を表示していません、コードを取得しているように、同じ方法でこの例外を処理できますか?
完全なコード:
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_camera);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
preview=(SurfaceView)findViewById(R.id.surface);
previewHolder=preview.getHolder();
previewHolder.addCallback(surfaceCallback);
previewHolder.setType(SurfaceHolder.SURFACE_TYPE_Push_BUFFERS);
btnCapture = (ImageButton) findViewById(R.id.btnCapture);
final MediaPlayer mp = MediaPlayer.create(CameraLauncherActivity.this, R.raw.button);
btnCapture.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mp.start();
camera.takePicture(null, null, mPicture);
}
});
@Override
public void onResume() {
super.onResume();
camera=Camera.open();
}
@Override
public void onPause() {
super.onPause();
if (inPreview) {
camera.stopPreview();
}
camera.release();
camera=null;
inPreview=false;
}
private Camera.Size getBestPreviewSize(int width, int height,
Camera.Parameters parameters) {
Camera.Size result=null;
for (Camera.Size size : parameters.getSupportedPreviewSizes()) {
if (size.width <= width && size.height <= height) {
if (result == null) {
result=size;
}
else {
int resultArea=result.width * result.height;
int newArea=size.width * size.height;
if (newArea > resultArea) {
result=size;
}
}
}
}
return(result);
}
private Camera.Size getSmallestPictureSize(Camera.Parameters parameters) {
Camera.Size result=null;
for (Camera.Size size : parameters.getSupportedPictureSizes()) {
if (result == null) {
result=size;
}
else {
int resultArea=result.width * result.height;
int newArea=size.width * size.height;
if (newArea < resultArea) {
result=size;
}
}
}
return(result);
}
SurfaceHolder.Callback surfaceCallback=new SurfaceHolder.Callback(){
public void surfaceCreated(SurfaceHolder holder) {
try {
camera.setPreviewDisplay(previewHolder);
} catch (Throwable t) {
Log.e("PreviewDemo-surfaceCallback",
"Exception in setPreviewDisplay()", t);
Toast.makeText(CameraLauncherActivity.this, t.getMessage(), Toast.LENGTH_LONG).show();
}
}
public void surfaceChanged(SurfaceHolder holder,int format, int width,int height) {
params = camera.getParameters();
params.setFlashMode(Camera.Parameters.FLASH_MODE_ON);
Camera.Size size = getBestPreviewSize(width, height, params);
Camera.Size pictureSize=getSmallestPictureSize(params);
if (size != null && pictureSize != null) {
params.setPreviewSize(size.width, size.height);
params.setPictureSize(pictureSize.width,
pictureSize.height);
camera.setParameters(params);
camera.startPreview();
inPreview=true;
}
}
public void surfaceDestroyed(SurfaceHolder holder) {
}
};
PictureCallback mPicture = new PictureCallback() {
@Override
public void onPictureTaken(byte[] data, Camera camera) {
pictureFile = getOutputMediaFile();
camera.startPreview();
if (pictureFile == null) {
return;
}
try {
FileOutputStream fos = new FileOutputStream(pictureFile);
fos.write(data);
fos.close();
} catch (FileNotFoundException e) {
} catch (IOException e) {
}
}
};
static File getOutputMediaFile() {
/* yyyy-MM-dd'T'HH:mm:ss.SSSZ */
timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss")
.format(new Date());
// file name
mediaFile = new File(LoginActivity.mediaStorageDir.getPath() + File.separator
+ "IMG_" + timeStamp + ".jpg");
return mediaFile;
}
}
まず、onPictureTakenで例外をキャッチします。空のキャッチセクションを残すことはお勧めできません。次に、前の画像が保存されている間にtakePicture()を呼び出さないようにするフラグを追加します。ボタンonClickの後で、takePicture()を呼び出しても問題ないかどうかを確認します。
アクティビティのメンバーとしてフラグを宣言します。
_private boolean safeToTakePicture = false;
_
surfaceChanged()
では、startPreview()を呼び出した後にフラグをtrueに設定するだけです。
_camera.startPreview();
safeToTakePicture = true;
_
onClick()
リスナーでフラグを確認し、OKの場合は写真を撮ります。
_if (safeToTakePicture) {
mp.start();
camera.takePicture(null, null, mPicture);
safeToTakePicture = false;
}
_
onPictureTaken()
で、画像が保存された後にフラグを再度trueに設定します(そして例外印刷を追加します):
_PictureCallback mPicture = new PictureCallback() {
@Override
public void onPictureTaken(byte[] data, Camera camera) {
pictureFile = getOutputMediaFile();
camera.startPreview();
if (pictureFile == null) {
//no path to picture, return
safeToTakePicture = true;
return;
}
try {
FileOutputStream fos = new FileOutputStream(pictureFile);
fos.write(data);
fos.close();
} catch (FileNotFoundException e) {
e.printStackTrace(); //<-------- show exception
} catch (IOException e) {
e.printStackTrace(); //<-------- show exception
}
//finished saving picture
safeToTakePicture = true;
}
};
_
注:ドキュメントが言うように、"写真を撮る前にプレビューを開始する必要があります。"。したがって、可能な拡張はsetPreviewCallback()を使用してプレビューデータが利用可能なときに呼び出され、onPreviewFrameが呼び出されたときにフラグをtrueに設定します。
私も同様の問題を抱えていました。後でstartPreview
が非常に重要であることがわかりました。
_camera.startPreview()
は、takePicutreがポイント5および6をチェックアウトする前に非常に重要です このリンク内 。
私の場合、これには多くの理由があります。プレビューなしで写真を撮ろうとして(隠された写真)、SurfaceView
を使用していたので、SurfaceTexture
に置き換えました
SurfaceTexture surfaceTexture = new SurfaceTexture(10);
camera.setPreviewTexture(surfaceTexture);
問題は解決しました... P.S 6.0以上のデバイスでのみこのエラーが発生していました
カメラでstartPreview()
を呼び出すのを忘れましたか?
詳細については、 here を参照してください。
この方法は、問題の解決に役立ちます。
private void safeCameraOpen(int id) {
try {
releaseCameraAndPreview();
mCamera = Camera.open(id);
} catch (Exception e) {
Log.e(getString(R.string.app_name), "failed to open Camera");
e.printStackTrace();
}
}
private void releaseCameraAndPreview() {
if (mCamera != null) {
mCamera.release();
mCamera = null;
}
}