2016-08-15 12 views
0

私は簡単な写真撮影のためのかなり標準的なプレビューとボタンを実装しました。サーフェスは、ラップトップのウェブカメラに接続されたエミュレータでも正常に動作します。 onPictureTaken()を実行する前に必ずプレビューを開始する必要があるため、問題は発生していません。Android Camera APIのtakePicture()はすぐに失敗します。サーフェスは正常に動作します

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): \t at android.hardware.Camera.native_takePicture(Native Method) 
 
08-15 13:51:27.365: E/AndroidRuntime(2738): \t at android.hardware.Camera.takePicture(Camera.java:1436) 
 
08-15 13:51:27.365: E/AndroidRuntime(2738): \t at com.davepeyton.android.seekbromance.BrofileCameraFragment$3.onClick(BrofileCameraFragment.java:106) 
 
08-15 13:51:27.365: E/AndroidRuntime(2738): \t at android.view.View.performClick(View.java:4780) 
 
08-15 13:51:27.365: E/AndroidRuntime(2738): \t at android.view.View$PerformClick.run(View.java:19866) 
 
08-15 13:51:27.365: E/AndroidRuntime(2738): \t at android.os.Handler.handleCallback(Handler.java:739) 
 
08-15 13:51:27.365: E/AndroidRuntime(2738): \t at android.os.Handler.dispatchMessage(Handler.java:95) 
 
08-15 13:51:27.365: E/AndroidRuntime(2738): \t at android.os.Looper.loop(Looper.java:135) 
 
08-15 13:51:27.365: E/AndroidRuntime(2738): \t at android.app.ActivityThread.main(ActivityThread.java:5254) 
 
08-15 13:51:27.365: E/AndroidRuntime(2738): \t at java.lang.reflect.Method.invoke(Native Method) 
 
08-15 13:51:27.365: E/AndroidRuntime(2738): \t at java.lang.reflect.Method.invoke(Method.java:372) 
 
08-15 13:51:27.365: E/AndroidRuntime(2738): \t at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903) 
 
08-15 13:51:27.365: E/AndroidRuntime(2738): \t 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

takePictureが非同期であるため、mJpegCallback内のアクティビティのハウスキーピングの問題は、おそらくあります。

これらのステートメントをonPause()に移動すると、予想通りに動作します。もちろん、現在のアクティビティが実際に破棄されていることを確認するために新しい写真が存在するかどうかチェックします。成功した写真が撮られた後の意図はどれですか。

関連する問題