屏幕关闭时Android相机不会拍照

Posted

技术标签:

【中文标题】屏幕关闭时Android相机不会拍照【英文标题】:Android Camera won't take picture when screen off 【发布时间】:2014-10-19 06:55:34 【问题描述】:

我有一个简单的应用程序,它有一个由警报管理器定期调用的活动,以显示预览框架并在构建预览框架时拍照。拍照后,使用AsyncTask 和使用finish() 销毁的活动。 当我打开屏幕时,代码工作得非常好。但是它无法在屏幕关闭的情况下拍照。我想监视一个房子并使用该应用程序定期拍照,在这种情况下保持屏幕始终打开或打开它手动开启不是一个可行的选择。

此外,相机活动的代码已从 Commonsware 库中复制,效果非常好。我只是在关闭屏幕的情况下拍照时遇到问题。我还可以从日志中看到相机由活动打开。但是,在构建预览帧时应该拍照的 Runnable 没有运行,而是相机进入暂停状态并停留在那里。

我已完美设置了必要的权限,因为我能够在屏幕打开的情况下获取图像。也许我在屏幕关闭时无法理解活动生命周期,并且有人可以在那里阐明。

我尝试使用唤醒锁打开屏幕,但没有任何好处。

以下是 Activity 的代码。

另外我很抱歉,但删除许可证的评论以使其简短。

    package com.thopedia.snapper; /***
 Copyright (c) 2008-2012 CommonsWare, LLC
*/
import all;

public class CameraActivity1 extends Activity 
    private PreviewFrameLayout frame=null;
    private SurfaceView preview=null;
    private SurfaceHolder previewHolder=null;
    private Camera camera=null;
    private boolean inPreview=false;
    private boolean cameraConfigured=false;
    private  PowerManager.WakeLock wakeLock;
    private PowerManager powerManager;

    @SuppressWarnings("deprecation")
    @Override
    public void onCreate(Bundle savedInstanceState) 
       /* powerManager = (PowerManager) getSystemService(POWER_SERVICE);
        wakeLock = powerManager.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, getClass()
                .getName());*/
        Log.v(GlobalVariables.TAG,"CameraActivity On create called");
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        frame=(PreviewFrameLayout)findViewById(R.id.frame);
        preview=(SurfaceView)findViewById(R.id.preview);
        previewHolder=preview.getHolder();
        previewHolder.addCallback(surfaceCallback);
        previewHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
     

    @TargetApi(Build.VERSION_CODES.GINGERBREAD)
    @Override
    public void onResume() 
       // wakeLock.acquire();
        Log.v(GlobalVariables.TAG,"camera activity onResume called");
       super.onResume();
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) 
            Camera.CameraInfo info=new Camera.CameraInfo();

            for (int i=0; i < Camera.getNumberOfCameras(); i++) 
                Camera.getCameraInfo(i, info);

                if (info.facing == Camera.CameraInfo.CAMERA_FACING_BACK) 
                    try
                        camera=Camera.open(i);
                    catch (Exception e)
                        Log.v(GlobalVariables.TAG,"Camera Opening Exception");
                        if(!isFinishing()) 
                            finish();
                        
        if (camera == null) 
            try
                camera=Camera.open();
            catch (Exception e)
                if(!isFinishing()) 
                    finish();
                
                Log.v(GlobalVariables.TAG,"Camera opening exception");
            
        

        startPreview();
        preview.post(new Runnable() 
            @Override
            public void run() 
                if (inPreview) 
                    camera.takePicture(null, null, photoCallback);
                    inPreview=false;
                
            
        );
    
    @Override
    public void onPause() 
        super.onPause();
        Log.v(GlobalVariables.TAG,"Camera activity onPause called");
        if (inPreview) 
            if(camera!=null) 
                camera.stopPreview();
            
        
        if(camera!=null) 
            camera.release();
            camera = null;
        
        inPreview=false;
    

    @Override
    protected void onDestroy() 
        Log.v(GlobalVariables.TAG,"Camera activity onDestroy called!");
        super.onDestroy();
        if(camera!=null)
            camera.release();
        
    

    @Override
    public boolean onCreateOptionsMenu(Menu menu) 
        new MenuInflater(this).inflate(R.menu.options, menu);
        return(super.onCreateOptionsMenu(menu));
    

    @Override
    public boolean onOptionsItemSelected(MenuItem item) 
        if (item.getItemId() == R.id.camera) 
            if (inPreview) 
                camera.takePicture(null, null, photoCallback);
                inPreview=false;
            
        
        return(super.onOptionsItemSelected(item));
    

    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);
    

    private void initPreview(int width, int height) 
        if (camera != null && previewHolder.getSurface() != null) 
            try 
                camera.setPreviewDisplay(previewHolder);
            
            catch (Throwable t) 
                Log.e("PreviewDemo-surfaceCallback",
                        "Exception in setPreviewDisplay()", t);
                Toast.makeText(CameraActivity1.this, t.getMessage(),
                        Toast.LENGTH_LONG).show();
            

            if (!cameraConfigured) 
                Camera.Parameters parameters=camera.getParameters();
                Camera.Size size=getBestPreviewSize(width, height, parameters);
                Camera.Size pictureSize=getSmallestPictureSize(parameters);

                if (size != null && pictureSize != null) 
                    parameters.setPreviewSize(size.width, size.height);
                    parameters.setPictureSize(pictureSize.width,
                            pictureSize.height);
                    parameters.setPictureFormat(ImageFormat.JPEG);
                    frame.setAspectRatio((double)size.width / size.height);
                    camera.setParameters(parameters);
                    cameraConfigured=true;
                
            
        
    

    private void startPreview() 
        if (cameraConfigured && camera != null) 
            camera.startPreview();
            inPreview=true;
        
    

    SurfaceHolder.Callback surfaceCallback=new SurfaceHolder.Callback() 
        public void surfaceCreated(SurfaceHolder holder) 
            // no-op -- wait until surfaceChanged()
        

        public void surfaceChanged(SurfaceHolder holder, int format,
                                   int width, int height) 
            initPreview(width, height);
            startPreview();
        

        public void surfaceDestroyed(SurfaceHolder holder) 
            // no-op
        
    ;

    Camera.PictureCallback photoCallback=new Camera.PictureCallback() 
        public void onPictureTaken(byte[] data, Camera camera) 
            new SavePhotoTask().execute(data);
            camera.startPreview();
            inPreview=true;
            if(!isFinishing()) 
                finish();
            
        
    ;

onResume().中正确创建预览表面后,我使用以下代码单击图片

preview.post(new Runnable() 
            @Override
            public void run() 
                if (inPreview) 
                    camera.takePicture(null, null, photoCallback);
                    inPreview=false;
                
            
        );

任何帮助表示赞赏。谢谢

【问题讨论】:

抱歉,这不是我的库支持的用例。 @CommonsWare 你认为这个问题有一个简单的解决方案吗?让活动在屏幕关闭的情况下拍照? 击败我。至少,您需要一个PARTIAL_WAKE_LOCK,否则设备完全处于睡眠状态。 【参考方案1】:

我认为您可以使用 WakeLock 来确保不会发生屏幕关闭。下面是示例代码/算法,您可以通过它在屏幕关闭时打开屏幕。希望这会有所帮助!

    在 Intent.ACTION_SCREEN_OFF 上注册广播接收器。

    每当您关闭广播意图时,请使用以下代码唤醒。

    PowerManager pm = (PowerManager) context
                            .getSystemService(Context.POWER_SERVICE);
                    WakeLock wakeLock = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK
                            | PowerManager.ACQUIRE_CAUSES_WAKEUP
                            | PowerManager.ON_AFTER_RELEASE, "MyWakeLock");
                    wakeLock.acquire();
    

【讨论】:

屏幕总是应该是关闭的。所以我不确定 Intent 是否会被触发。我尝试获取 Partial_WAKE_LOCK 和 SCREEN 锁定也不起作用。我会尝试你的代码看看它是否有效。谢谢【参考方案2】:
android:keepScreenOn="true" 

您可以将上面的行用于您通过活动调用的 XML 中的父布局

它会让你的屏幕一直亮着,这样你就不会遇到任何问题,希望它符合你的要求

【讨论】:

【参考方案3】:

在大量使用 LogCat 之后,我发现了问题所在:)。

似乎当屏幕保持打开时,onPause() 不会立即被调用,SCREEN_OFF 就是这种情况。当 屏幕打开时,Runnable 被执行在执行onPause() 方法之前,因此拍摄的照片非常好。但是,如果屏幕关闭,则在Activity 完成onPause() 方法后执行Runnable。通过这次我们已经在onPause()发布了相机,所以我们没有拍照。

在我弄清楚流程并将相机释放移动到onDestroy() 后它开始工作,这可能并不适合所有情况,但对我来说效果很好,因为我的活动的唯一目的是拍照然后毁灭自己。

WAKELOCKS 也没有改变代码的行为。我希望 Activity 在没有 WAKE_LOCK 的情况下不会执行,但它工作得很好。

希望这可以帮助陷入类似情况的人。

【讨论】:

以上是关于屏幕关闭时Android相机不会拍照的主要内容,如果未能解决你的问题,请参考以下文章

Android在后台运行任务时关闭屏幕

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

Android 相机 takePicture() 失败

Android 相机预览在预览中拉伸,而不是在拍照后

即使 autoRotation 关闭,也能获取 android 设备方向

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