【问题标题】:Strobe light camera parameters? Why is My app crashing?频闪灯相机参数?为什么我的应用程序崩溃?
【发布时间】:2014-03-29 08:11:26
【问题描述】:

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

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

这是我的宝贝!我困扰了你们 2 周,试图弄清楚如何进行这个特定的实现。

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

}

【问题讨论】:

    标签: android multithreading android-camera


    【解决方案1】:

    您需要确保在活动暂停或暂停时松开相机。这一点很重要,因为一次只允许一个 Activity 拥有对摄像头的访问权限,并且如果您的 Activity 在它终止之前从未释放它,那么您的摄像头实际上是无用的,直到您重新启动手机。

    另外,请务必在您的 CountDownTimer 上致电 .cancel()

    // YourActivity.java
    @Override
    public void onPause(){
        super.onPause();
    
        if(superStrobe != null){
            superStrobe.cancel();
        }
    
        if(camera != null){
            camera.release();
            camera = null;
        }
    }
    

    编辑 2

    我花了一些时间为您的应用构建了效果,并确保它能够干净利落地处理自己。不错的频闪!因此,您需要牢记以下几点:

    1. 相机在处理时需要特别小心,因此您需要谨慎设置和拆卸 Activity。

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

    3. 一般来说,最好在 .onResume() 中设置 Activity,在 .onPause() 中进行拆卸

    我将跳过您似乎已经理解的部分,但为您和其他发现此内容的人指出一些非常重要的注意事项。

    因为处理 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;
        }
    }
    

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

    希望这对不同经验水平的人有所帮助。其中一些可能看起来像黑魔法,但我已尽力解释其背后的原因

    【讨论】:

    • 好的!我正在使用 if (camera != null) { camera.release();相机=空;在 onDestroy() 所以.. 让我现在解决这个问题.. 谢谢人! @scriptocalypse
    • onDestroy() 绝对不够快。在 Activity 停止执行任何操作时立即释放相机是最好的做法,这通常是 onPause()。
    • 这实际上带来了更多问题。 . @scriptocalypse 你看到它在哪里说 camera.setParameters(p);就在 } else { .. 下,它表示未处理的异常。这没有任何意义,因为它只是在工作..我知道当活动开始时相机不会自动设置为暂停..
    • 查看编辑。您还需要取消您的 superStrobe。
    • 我想我可以编辑你的答案,但我想我不能..请查看我修改后的问题..感谢你的帮助,但这些解决方案不起作用..但我相信你知道解决办法。只是也许您需要更好地查看代码。 @scriptocalypse
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-30
    • 1970-01-01
    • 1970-01-01
    • 2018-04-03
    相关资源
    最近更新 更多