频闪灯相机参数?为什么我的应用程序崩溃了?

时间:2014-03-27 15:46:20

标签: android multithreading android-camera

我在Google上有几个应用程序。

在这些应用程序中,我有一个闪光灯,当用户按下按钮时会运行。 问题是,当我切换活动时,应用程序崩溃了。由于在用户按下时相机的参数设置为开,我得到了一些帮助。这意味着当他们进入下一个要求摄像头的活动时,应用程序会崩溃。我甚至在手机上下载了应用程序,有时手机也停止响应。我试图弄清楚为什么我自己的手机开始行动,我发现我的应用程序导致了这些问题。

这是我的宝贝!我试图弄清楚如何制作这个特定的实现,我们两个星期的时间。

    public void strobeTimer182() {
    superStrobe = new CountDownTimer(857, 1) {

        public void onTick(long millisUntilFinished) {
            if (millisUntilFinished % 2 == 0) {

                p.setFlashMode(Parameters.FLASH_MODE_TORCH);
                camera.setParameters(p);
                camera.startPreview();
                p.setFlashMode(Parameters.FLASH_MODE_OFF);
                camera.setParameters(p);
                camera.stopPreview();

            } else {

                p.setFlashMode(Parameters.FLASH_MODE_TORCH);
                camera.setParameters(p);
                camera.startPreview();
                p.setFlashMode(Parameters.FLASH_MODE_OFF);
                camera.setParameters(p);
                camera.stopPreview();
                 crazy.nextInt(265)));
            }
            if (millisUntilFinished == 0) {

                p.setFlashMode(Parameters.FLASH_MODE_TORCH);
                camera.setParameters(p);
                camera.startPreview();
                p.setFlashMode(Parameters.FLASH_MODE_OFF);
                camera.setParameters(p);
                camera.stopPreview();

            }

        }

我已经读过它了,因为当手机预计它们关闭时,相机的参数会打开。

我的问题是。为什么会这样呢?您可以在代码中看到if语句应该完全转换它。

这里是一些关于错误的代码。

这是我的onStart()

@Override
protected void onStart() {
    super.onStart();
     // on starting the app get the camera params
    getCamera();
    // turnOffFlash();
}

和getCamera()"按钮"是按钮上的切换摄像头。所以当应用程序启动时......你必须打开它。有些手机不能正常使用相机,所以我想我必须首先检查..当你按下其他按钮时......音乐播放和频闪播放857毫秒......你可以看到。

public void getCamera(){

Context context = this;
// Retrieve application packages that are currently installed
// on the device which includes camera, GPS etc.
PackageManager pm = context.getPackageManager();

if (!pm.hasSystemFeature(PackageManager.FEATURE_CAMERA)) {
    Log.e("err", "Device has no camera!"); // Toast a message to let the
    // user know that camera is not // installed in the device
    Toast.makeText(getApplicationContext(),
            "Your device doesn't have camera!",         Toast.LENGTH_SHORT)
            .show();
    button.setEnabled(false);

    // Return from the method, do nothing after this code block
    return;
} else {

    camera = Camera.open();
    p = camera.getParameters();
}

}

1 个答案:

答案 0 :(得分:3)

您需要确保在活动暂停或暂停时释放相机。这很重要,因为一次只允许一项活动拥有对摄像机的访问权限,如果您的活动在死亡之前从未释放,那么在您重新启动手机之前,您的摄像机实际上是无用的。

另外,请务必在CountDownTimer上调用.cancel()

// YourActivity.java
@Override
public void onPause(){
    super.onPause();

    if(superStrobe != null){
        superStrobe.cancel();
    }

    if(camera != null){
        camera.release();
        camera = null;
    }
}

编辑2

我花了一些时间来构建你的应用程序的效果,并确保它干净利落地处理。好闪光!所以,这里有一些你真正需要记住的事情:

  1. 相机需要特别小心处理,因此您需要对如何设置和拆除活动一丝不苟。

  2. 使用旨在安全处理资源的特定方法对您有很大帮助。尝试永远不要处理你的相机或你的计时器,除非你通过方法安全地检查他们在做什么之前做了什么。

  3. 一般情况下,最好在.onResume()进行活动设置,并在.onPause()

  4. 中进行拆分

    我会跳过你似乎已经理解的部分,但是为你和其他发现这一点的人提出一些非常重要的考虑因素。

    因为处理Android相机有点危险,你会想要这样的方法,它们应该成对出现。一个用于创建资产,另一个用于清理它们:

    // Ways to safely access the camera...
    safelyAcquireCamera()
    safelyReleaseCamera()
    
    // Ways to safely access the timer...
    startTimer()
    stopTimer()
    
    // Ways to setup your button...
    setupButton()
    
    // Special error handling code that makes sure to clean up the Activity if it crashes.
    setupUncaughtExceptionHandler()
    restoreOriginalUncaughtExceptionHandler()
    

    你会想要像这样的变量

    Camera camera;
    Camera.Parameters cameraParameters;
    CountDownTimer countDownTimer;
    UncaughtExceptionHandler originalExceptionHandler;
    boolean timerIsStarted = false;
    

    我会为你解决这个问题。这可能看起来相当很长,但这里有很多概念:

    @Override
    public void onResume() {
        super.onResume();
    
        this.setupUncaughtExceptionHandler(); 
            // ^^ Super important!  ^^
            // This saves you if you crash!
    
    
        boolean didAcquireCamera = safelyAcquireCamera();
    
        setupButton(didAcquireCamera);
            // ^^ Set up your button, letting the 
            // method know if you succeeded in acquiring the camera.
            // you probably know how to implement this already. 
    
    }
    
    @Override
    public void onPause() {
        super.onPause();
    
        stopTimer();
            // FIRST stop your timer.  Even though the timer has logic that
            // accounts for you doing this out of order, it's still correct 
            // to stop your running action first.
    
        safelyReleaseCamera();
            // Now you should release your camera using your safe method.
    
        releaseButtons();
            // Release your buttons...
    
        restoreOriginalUncaughtExceptionHandler(); 
            // ^^ Since you safely cleaned up your Activity
            // it is s time to restore the Exception Handler.
    }
    
    protected void stopTimer() {
        // This method gives you a safe way to stop the timer.
        if (countDownTimer != null) {
            countDownTimer.cancel();
            countDownTimer = null;
            timerIsStarted = false;
        }
    }
    
    protected void safelyReleaseCamera() {
    
        // This method gives you a safe way to release the camera.
        if (camera != null) {
    
            // You probably want to make sure to turn the flash off
            // if you had it on already!
            if (cameraParameters != null) {
                cameraParameters.setFlashMode(Parameters.FLASH_MODE_OFF);
                camera.setParameters(cameraParameters);
                camera.stopPreview();
            }
    
            camera.release();
            camera = null;
            cameraParameters = null;
    
        }
    
    }
    
    protected boolean safelyAcquireCamera() {
        safelyReleaseCamera();
          // ^^ It's very important to make sure your app DOES NOT
          // have a stray camera before you try to acquire a new one!
          // Be absolutely sure to call safe release before you try to 
          // call Camera.open(); here.
    
    
        /**
         * You seem to know how to acquire the camera already.  Just
         * return true if you succeeded and false if you didn't.
         **/
    
    
        return camera != null;
    }
    
    
    protected void startTimer(long millisInTheFuture, long countDownInterval) {
        stopTimer();
        timerIsStarted = true;
        countDownTimer = new CountDownTimer(millisInTheFuture, countDownInterval) {
    
            @Override
            public void onTick(long millisUntilFinished) {
                if (camera == null || cameraParameters == null) {
                    stopTimer();
                    return;
                      // Clearly things have gone awry if you lost your camera!  
                      // Bail Out.
                }
    
                /**
                 * Do your strobing like normal in here...
                 **/
    
            }
    
            @Override
            public void onFinish() {
                timerIsStarted = false;
            }
        };
        countDownTimer.start();
    }
    
    protected void setupButtons(boolean didAcquireCamera){
    
        /**
         *  You seem to have a good handle on
         *  how to set up a button.  Make it so!
         **/
    
    }
    
    protected void releaseButtons(){
        // And here you should safely set all your button handlers to null!
    }
    
    /*****************
     * Safety Methods
     *   This might be advanced, but I'll try to make it simple.
     *****************/
    
    private void setupUncaughtExceptionHandler() {
    
        restoreOriginalUncaughtExceptionHandler();
            // ^^ Ensure that you're in as close to a default state as you can.
    
        Thread currentlyRunningThread = Thread.currentThread();
        originalExceptionHandler = currentlyRunningThread.getUncaughtExceptionHandler();
            // ^^ This is the thing that happens when your app normally crashes.
            // You'll be giving it a new, special set of instructions in this case,
            // but you'll still want to hold onto the default implmenetation.
    
        currentlyRunningThread.setUncaughtExceptionHandler(new UncaughtExceptionHandler() {
    
            @Override
            public void uncaughtException(Thread thread, Throwable ex) {
    
                stopTimer();
                safelyReleaseCamera();
                    // ^^ You don't know how or why you crashed.
                    // So call your safe disposal methods here!
    
                releaseButtons();
    
                if(originalExceptionHandler != null){
                    originalExceptionHandler.uncaughtException(thread, ex);
                        // Now make sure you call the original handler so that 
                        // Android does its normal crash thing.
                }
    
                thread.setUncaughtExceptionHandler(originalExceptionHandler);
                    // And restore the original crash behavior to be the default.
    
            }
    
        });
    }
    
    private void restoreOriginalUncaughtExceptionHandler() {
        if (originalExceptionHandler != null) {
            Thread.currentThread().setUncaughtExceptionHandler(originalExceptionHandler);
            originalExceptionHandler = null;
        }
    }
    

    您可能需要滚动上面的代码区域。

    希望这对各种经验水平的人都有帮助。其中一些可能看起来像黑魔法,但我已尽力解释背后的为什么