Android相机在屏幕关闭时无法拍照。

5
我有一个简单的应用程序,定期通过警报管理器调用活动来显示预览框架并在构建预览框架时拍照。拍照后,使用AsyncTask保存照片,并使用finish()销毁活动。当屏幕打开时,代码运行得非常好。但是,在关闭屏幕时无法拍照。我想使用该应用程序监视房屋并定期拍照,在这种情况下,始终保持屏幕开启或手动开启不是可行的选择。
此外,相机活动的代码已从Commonsware库复制,并且运行非常完美。但是,我在关闭屏幕时拍照遇到了问题。我还可以从日志中看到相机由活动打开。但是,当构建预览帧时应该拍照的Runnable不运行,相机进入暂停状态并停留在那里。
我已经完美设置了必要的权限,因为我能够在打开屏幕时获取图像。也许我在理解屏幕关闭时的活动生命周期方面遇到了麻烦,希望有人能提供帮助。
我尝试使用wakelocks将屏幕打开,但没有任何好处。
以下是该活动的代码。
还有,抱歉但是为了缩短这里的长度,我将删除许可证的注释。
    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;
                }
            }
        });

Any help is appreciated.Thanks


抱歉,但这不是我的库支持的用例。 - CommonsWare
@CommonsWare您认为有没有简单的解决方案来解决这个问题呢?让一个活动在关闭屏幕的情况下拍照? - SteveIrwin
我不知道。至少,你需要一个PARTIAL_WAKE_LOCK,否则设备会完全休眠。 - CommonsWare
3个回答

1

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

  1. 在Intent.ACTION_SCREEN_OFF上注册广播接收器。
  2. 每当您收到屏幕关闭的广播意图时,使用以下代码唤醒:

    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 on lock,但都没有起作用。不过我会尝试你的代码,看看是否有效。谢谢。 - SteveIrwin

1
android:keepScreenOn="true" 

您可以将上述代码行添加到您通过Activity调用的父布局的XML中

它将始终保持屏幕开启,因此您不会遇到任何问题,希望它符合您的要求


1

在广泛使用LogCat后,我找到了问题所在 :)

似乎当屏幕保持开启状态时,onPause()不会立即调用,而SCREEN_OFF则相反。当屏幕为ON时,RunnableonPause()方法执行之前被执行,因此图片可以完美地拍摄。然而,在屏幕为OFF的情况下,Runnable在Activity完成onPause()方法后才被执行。此时我们已经在onPause()中释放了相机,因此我们无法得到一张照片。

在我理解流程并将相机释放到onDestroy()后,它开始正常工作。这可能并不适用于所有情况,但对我的情况来说完全可行,因为我Activity的唯一目的是拍照然后销毁自己。

此外,WAKE_LOCKS没有改变代码的行为。我预期Activity在没有WAKE_LOCK的情况下不会执行,但它完美地工作了。

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接