Android 相机 - 有时当我拍照时,应用程序冻结并且相机无法使用

Posted

技术标签:

【中文标题】Android 相机 - 有时当我拍照时,应用程序冻结并且相机无法使用【英文标题】:Android Camera - Sometimes when i take photos, the app freezes and the camera is non-usable 【发布时间】:2012-03-29 01:20:50 【问题描述】:

我已经构建了一个应用程序,当您触摸预览时会拍照。 我可以拍很多照片,但有时当我触摸预览拍照时,没有快门声,整个应用程序冻结。此外,在此之后,如果我尝试启动内置相机应用程序,我会收到无法使用相机的消息。

我不知道这种行为的原因,它是随机发生的,当它发生时,我必须重新启动设备(三星 Galaxy S)才能再次使用相机。

在 DDM 中,崩溃后我可以看到以下行:keyDispatchingTimedOut

以下是相关代码: CameraActivity 类:

public class CameraActivity extends Activity 
  private static final String TAG = "CameraDemo";
  Preview preview;

  public void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    preview = new Preview(this);
    ((FrameLayout) findViewById(R.id.preview)).addView(preview);
    ((FrameLayout) findViewById(R.id.preview)).setOnTouchListener(preview); 

    Log.d(TAG, "Camera Activity Created.");

  

预习课:

    class Preview extends SurfaceView implements SurfaceHolder.Callback, OnTouchListener 
    private static final String TAG = "Preview";

    SurfaceHolder mHolder;
    public Camera camera;
    Context ctx;
    boolean previewing = false;

    Preview(Context context) 
        super(context);
        ctx = context;
        // Install a SurfaceHolder.Callback so we get notified when the
        // underlying surface is created and destroyed.
        mHolder = getHolder();
        mHolder.addCallback(this);
        mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    


    // Called once the holder is ready
    public void surfaceCreated(SurfaceHolder holder) 
        // The Surface has been created, acquire the camera and tell it where
        // to draw.
        camera = Camera.open();
    

    // Called when the holder is destroyed
    public void surfaceDestroyed(SurfaceHolder holder) 

        if (camera != null) 
            camera.setPreviewCallback(null);
            camera.stopPreview();  
            camera.release();
            camera = null;
        

        previewing = false;
    

    // Called when holder has changed
    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) 

        if(previewing)
             camera.stopPreview();
             previewing = false;
        

        if (camera != null)
            try 

                camera.setDisplayOrientation(90);
                camera.setPreviewDisplay(holder);
                camera.setPreviewCallback(new PreviewCallback() 
                    // Called for each frame previewed
                    public void onPreviewFrame(byte[] data, Camera camera) 
                        Log.d(TAG, "onPreviewFrame called at: " + System.currentTimeMillis());  
                        Preview.this.invalidate();
                    
                );
                camera.startPreview();
                previewing = true;
             catch (IOException e) 
                // TODO Auto-generated catch block
                e.printStackTrace();
            
        
    

    public boolean onTouch(View v, MotionEvent event) 
        camera.takePicture(shutterCallback, rawCallback, jpegCallback);
        return false;
    


    // Called when shutter is opened
    ShutterCallback shutterCallback = new ShutterCallback() 
        public void onShutter() 
            Log.d(TAG, "onShutter'd");
        
    ;

    // Handles data for raw picture
    PictureCallback rawCallback = new PictureCallback() 
        public void onPictureTaken(byte[] data, Camera camera) 
            Log.d(TAG, "onPictureTaken - raw");
        
    ;

    // Handles data for jpeg picture
    PictureCallback jpegCallback = new PictureCallback() 

        public void onPictureTaken(byte[] data, Camera camera) 
            FileOutputStream outStream = null;
            try 
                // Write to SD Card
                outStream = new FileOutputStream(String.format("/sdcard/TVguide/Detection/detected.jpg", System.currentTimeMillis())); // <9>
                outStream.write(data);
                outStream.close();
                Log.d(TAG, "onPictureTaken - wrote bytes: " + data.length);
             catch (FileNotFoundException e)  // <10>
                //Toast.makeText(ctx, "Exception #2", Toast.LENGTH_LONG).show();
                e.printStackTrace();
             catch (IOException e) 
                e.printStackTrace();
             finally 
            Log.d(TAG, "onPictureTaken - jpeg");
            Toast.makeText(ctx, "SAVED", Toast.LENGTH_SHORT).show();

            camera.startPreview();
        
    ;


请帮忙,我正在尝试几天来了解问题出在哪里,但没有成功

艾尔

【问题讨论】:

我也建议将图片保存到 sd 卡,以便在后台线程中制作,而不是在主 UI 线程中。 【参考方案1】:

我在三星 Galaxy SII 上测试我的应用程序时遇到了这个问题。您只需在拍照前删除预览回调即可:

mCamera.setPreviewCallback(null);
mCamera.takePicture(null, null, mPictureCallback);

【讨论】:

在 HTC Sensation 上,我的自定义相机应用程序在全屏空间显示预览。当用户点击屏幕时,会调用焦点。当焦点完成并成功时,我调用 mCamera.takePicture 。有时它可以工作,我得到保存 JPG 数据的回调,其他时候它只是停留在 takePicture 中,没有超时也没有任何调试消息。这太烦人了,每次都要重启手机,不知道问题出在哪里。 SettingsPreviewCallback 到 null 没有帮助。还有其他想法吗?【参考方案2】:

我不知道导致该错误的原因,如果您从发生此错误的时间发布 loggcat 输出,它真的会有所帮助。

但是,我可以做一些猜测。看起来相机被锁定(内置相机不起作用)。如果您的应用程序强制关闭,则相机锁定可能是由三星相机 HAL 中的错误错误处理引起的。尤其是在 Galaxy S 等较旧的手机中,它们在处理错误或不标准的 API 调用方面做得并不好。

以下是可能导致此行为的一些建议:

    你应该为拍照添加一个警卫。现在,如果您触摸屏幕并拍照,您可以在拍照完成之前再次触摸屏幕。因此,camera.takePicture() 将被调用两次。第二个会失败。这是我最好的猜测。

    添加一些boolean isTakingPicture = false变量然后:

    public boolean onTouch(View v, MotionEvent event) 
      if (!isTakingPicture) 
        camera.takePicture(shutterCallback, rawCallback, jpegCallback);
        isTakingPicture = true;
      
      return false;
    
    ...
    public void onPictureTaken(byte[] data, Camera camera) 
      isTakingPicture = false;
      ...
    

    您使用 previewCallback 做什么?我在这里没有做任何有用的事情。预览回调有时会引起一些痛苦,尽管您的代码对我来说看起来不错。您可以随时尝试删除它并检查是否有帮助。

【讨论】:

太棒了!第一个解决方案没有帮助,但第二个解决方案(删除 previewCallback)解决了问题 嗯,也许在分配给相机的 SurfaceView 上调用 invalidate() 是问题所在。我从来没有尝试过,我无法想象有任何阅读可以做到这一点。不过,我认为您也应该应用第一个解决方案,以防止潜在的错误。【参考方案3】:

我遇到了此处报告的类似问题。在 LG p705 和三星 Galaxy Trend 上,拍照后,预览被冻结,相机无法再使用,直到手机重新启动。然而,在 Galaxy S3 上,即使在拍摄了多张照片后,预览也会继续正常显示。

在调试时,我注意到当按下相机按钮拍照时,相关的侦听器类收到了多个调用。我不确定为什么它会被调用两次,即使按钮只单击一次。在任何情况下,由于 Tomasz 建议使用布尔变量,第二次调用会在第一次尝试进行时跳过拍照。也感谢 Eyal 的提问。 :)

【讨论】:

以上是关于Android 相机 - 有时当我拍照时,应用程序冻结并且相机无法使用的主要内容,如果未能解决你的问题,请参考以下文章

以编程方式在 Android 上使用相机拍照

Phonegap|Android 4 - 从 PHOTOLIBRARY 拍照时,应用程序有时会崩溃

拍照时有时不会播放相机快门噪音。

在 Android 6.0 中缺乏访问相机服务的权限

故意相机崩溃

Android调用照相机和百度地图开发,百度地图显示界面覆盖了相机界面,求大神解答?