Search code examples
javaandroidonresume

Application Crashes when resuming the app


I am creating a simple Flashlight App, but every time I leave the app and reopen it, it crashes. Am I missing something in my code, because I am not sure what, below is an error when it crashes. Please let me know what I need to do in order to fix this resume issue:

package com.example.gkvxm.materiallight;

import android.animation.ValueAnimator;
import android.app.Activity;
import android.content.Context;
import android.content.pm.PackageManager;
import android.hardware.Camera;
import android.os.Bundle;
import android.util.Log;
import android.view.KeyEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.widget.Toast;

import com.dd.CircularProgressButton;

import java.io.IOException;


public class FlashLightActivity extends Activity implements SurfaceHolder.Callback {

    private boolean isLigtOn = false;

    private Camera camera;

    @Override
    protected void onStart(){
        super.onStart();

        SurfaceView preview = (SurfaceView)findViewById(R.id.PREVIEW);
            SurfaceHolder mHolder = preview.getHolder();
        mHolder.addCallback(this);
    }

    @Override
    protected void onStop(){
        super.onStop();

        if(camera!=null){
            camera.release();
        }
    }
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_flash_light);

        Context context = this;
        PackageManager pm = context.getPackageManager();

        if (!pm.hasSystemFeature(PackageManager.FEATURE_CAMERA)) {
            Toast.makeText(FlashLightActivity.this, "Your Device is not supported", Toast.LENGTH_SHORT).show();
            Log.e("err", "Device is not supported");
            return;
        }

        camera = Camera.open();
        final Camera.Parameters p = camera.getParameters();


        final CircularProgressButton circularButton1 = (CircularProgressButton) findViewById(R.id.btnWithText);
       circularButton1.setIndeterminateProgressMode(true);
        circularButton1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (isLigtOn) {
                    turnOffFlash(p);
                    Toast.makeText(FlashLightActivity.this, "Lights Off!", Toast.LENGTH_SHORT).show();

                } else {
                    turnOnFlash(p);
                    Toast.makeText(FlashLightActivity.this, "Lights On!", Toast.LENGTH_SHORT).show();

                }

                if (circularButton1.getProgress() == 0) {
                    simulateSuccessProgress(circularButton1);
                } else {
                    circularButton1.setProgress(0);
                }
            }
        });
    }

    private void turnOnFlash(Camera.Parameters p){
        p.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);

        camera.setParameters(p);
        camera.startPreview();
        isLigtOn = true;
    }
    private void turnOffFlash(Camera.Parameters p){
        p.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
        camera.setParameters(p);
        camera.stopPreview();
        isLigtOn = false;
    }
    @Override
    public void surfaceChanged(SurfaceHolder holder,int format,int width,int height){

    }
    @Override
    public void surfaceCreated(SurfaceHolder holder){
        try{
            Log.i("SurfaceHolder","Setting preview");
            camera.setPreviewDisplay(holder);
        } catch (IOException e){
            e.printStackTrace();
        }
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder){
        Log.i("SurfaceHOlder", "stopping preview");
        camera.stopPreview();
        holder = null;
    }

    private void simulateSuccessProgress(final CircularProgressButton button) {
        ValueAnimator widthAnimation = ValueAnimator.ofInt(1, 100);
        widthAnimation.setDuration(1500);
        widthAnimation.setInterpolator(new AccelerateDecelerateInterpolator());
        widthAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                Integer value = (Integer) animation.getAnimatedValue();
                button.setProgress(value);
            }
        });
        widthAnimation.start();
    }

    private void simulateErrorProgress(final CircularProgressButton button) {
        ValueAnimator widthAnimation = ValueAnimator.ofInt(1, 99);
        widthAnimation.setDuration(1500);
        widthAnimation.setInterpolator(new AccelerateDecelerateInterpolator());
        widthAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                Integer value = (Integer) animation.getAnimatedValue();
                button.setProgress(value);
                if (value == 99) {
                    button.setProgress(-1);
                }
            }
        });
        widthAnimation.start();
    }


}

Error :

05-22 03:08:35.646  13909-13909/com.example.gkvxm.materiallight E/AndroidRuntime﹕ FATAL EXCEPTION: main
    Process: com.example.gkvxm.materiallight, PID: 13909
    java.lang.RuntimeException: Camera is being used after Camera.release() was called
            at android.hardware.Camera._stopPreview(Native Method)
            at android.hardware.Camera.stopPreview(Camera.java:732)
            at com.example.gkvxm.materiallight.FlashLightActivity.surfaceDestroyed(FlashLightActivity.java:129)
            at android.view.SurfaceView.updateWindow(SurfaceView.java:564)
            at android.view.SurfaceView.onWindowVisibilityChanged(SurfaceView.java:238)
            at android.view.View.dispatchWindowVisibilityChanged(View.java:8785)
            at android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.java:1164)
            at android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.java:1164)
            at android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.java:1164)
            at android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.java:1164)
            at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1318)
            at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1061)
            at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:5885)
            at android.view.Choreographer$CallbackRecord.run(Choreographer.java:767)
            at android.view.Choreographer.doCallbacks(Choreographer.java:580)
            at android.view.Choreographer.doFrame(Choreographer.java:550)
            at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:753)
            at android.os.Handler.handleCallback(Handler.java:739)
            at android.os.Handler.dispatchMessage(Handler.java:95)
            at android.os.Looper.loop(Looper.java:135)
            at android.app.ActivityThread.main(ActivityThread.java:5254)
            at java.lang.reflect.Method.invoke(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:372)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)

Solution

  • Camera is being used after Camera.release() was called. So, looking at the activity lifecycle, you need to open the camera in onStart() or in onRestart(). So Maybe this code will work fine ...

    package com.example.gkvxm.materiallight;
    
    import android.animation.ValueAnimator;
    import android.app.Activity;
    import android.content.Context;
    import android.content.pm.PackageManager;
    import android.hardware.Camera;
    import android.os.Bundle;
    import android.util.Log;
    import android.view.KeyEvent;
    import android.view.SurfaceHolder;
    import android.view.SurfaceView;
    import android.view.View;
    import android.view.animation.AccelerateDecelerateInterpolator;
    import android.widget.Toast;
    
    import com.dd.CircularProgressButton;
    
    import java.io.IOException;
    
    
    public class FlashLightActivity extends Activity implements SurfaceHolder.Callback {
    
        private boolean isLigtOn = false;
    
        private Camera camera;
    
        @Override
        protected void onStart(){
            super.onStart();
             camera = Camera.open();
        final Camera.Parameters p = camera.getParameters();
            SurfaceView preview = (SurfaceView)findViewById(R.id.PREVIEW);
                SurfaceHolder mHolder = preview.getHolder();
            mHolder.addCallback(this);
        }
    
        @Override
        protected void onStop(){
            super.onStop();
    
            if(camera!=null){
                camera.release();
            }
        }
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_flash_light);
    
            Context context = this;
            PackageManager pm = context.getPackageManager();
    
            if (!pm.hasSystemFeature(PackageManager.FEATURE_CAMERA)) {
                Toast.makeText(FlashLightActivity.this, "Your Device is not supported", Toast.LENGTH_SHORT).show();
                Log.e("err", "Device is not supported");
                return;
            }
    
            camera = Camera.open();
            final Camera.Parameters p = camera.getParameters();
    
    
            final CircularProgressButton circularButton1 = (CircularProgressButton) findViewById(R.id.btnWithText);
           circularButton1.setIndeterminateProgressMode(true);
            circularButton1.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    if (isLigtOn) {
                        turnOffFlash(p);
                        Toast.makeText(FlashLightActivity.this, "Lights Off!", Toast.LENGTH_SHORT).show();
    
                    } else {
                        turnOnFlash(p);
                        Toast.makeText(FlashLightActivity.this, "Lights On!", Toast.LENGTH_SHORT).show();
    
                    }
    
                    if (circularButton1.getProgress() == 0) {
                        simulateSuccessProgress(circularButton1);
                    } else {
                        circularButton1.setProgress(0);
                    }
                }
            });
        }
    
        private void turnOnFlash(Camera.Parameters p){
            p.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);
    
            camera.setParameters(p);
            camera.startPreview();
            isLigtOn = true;
        }
        private void turnOffFlash(Camera.Parameters p){
            p.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
            camera.setParameters(p);
            camera.stopPreview();
            isLigtOn = false;
        }
        @Override
        public void surfaceChanged(SurfaceHolder holder,int format,int width,int height){
    
        }
        @Override
        public void surfaceCreated(SurfaceHolder holder){
            try{
                Log.i("SurfaceHolder","Setting preview");
                camera.setPreviewDisplay(holder);
            } catch (IOException e){
                e.printStackTrace();
            }
        }
    
        @Override
        public void surfaceDestroyed(SurfaceHolder holder){
            Log.i("SurfaceHOlder", "stopping preview");
            camera.stopPreview();
            holder = null;
        }
    
        private void simulateSuccessProgress(final CircularProgressButton button) {
            ValueAnimator widthAnimation = ValueAnimator.ofInt(1, 100);
            widthAnimation.setDuration(1500);
            widthAnimation.setInterpolator(new AccelerateDecelerateInterpolator());
            widthAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    Integer value = (Integer) animation.getAnimatedValue();
                    button.setProgress(value);
                }
            });
            widthAnimation.start();
        }
    
        private void simulateErrorProgress(final CircularProgressButton button) {
            ValueAnimator widthAnimation = ValueAnimator.ofInt(1, 99);
            widthAnimation.setDuration(1500);
            widthAnimation.setInterpolator(new AccelerateDecelerateInterpolator());
            widthAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    Integer value = (Integer) animation.getAnimatedValue();
                    button.setProgress(value);
                    if (value == 99) {
                        button.setProgress(-1);
                    }
                }
            });
            widthAnimation.start();
        }
    }