Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

surfaceCreated() Never Called

I've seen similar problems to the one I'm having, but I still can't find a solution. I'm very new to Android development, so I'm having trouble tracking down my problem. Anyways, I'm trying to create a camera preview using a CameraSurfaceView class I created that extends SurfaceView and implements SurfaceHolder.Callback. No matter what I try in my StartCamera class, the surfaceCreated() method is never called, hence my camera never starts. Any help would be great, thanks!

StartCamera.java

import net.peterd.zombierun.R;
import android.hardware.Camera;
import android.os.Bundle;
import android.widget.FrameLayout;

public class StartCamera extends BaseActivity {

    private Camera mCamera;
    private CameraSurfaceView mView;

    public void onCreate(Bundle state) {
        // TODO Auto-generated constructor stub
        super.onCreate(state);
        setContentView(R.layout.start_camera);
    }

    public void onResume() {
        super.onResume();

        mView = new CameraSurfaceView(this);
        FrameLayout preview = (FrameLayout) findViewById(R.id.cPreview);
        preview.addView(mView);
    }

    public void onPause() {
        mCamera.stopPreview();
        mCamera.release();
    }

}

CameraSurfaceView.java

import java.io.IOException;
import android.content.Context;
import android.hardware.Camera;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

public class CameraSurfaceView extends SurfaceView implements SurfaceHolder.Callback
{
        private SurfaceHolder holder;
        private Camera camera;

        public CameraSurfaceView(Context context) 
        {
                super(context);

                //Initiate the Surface Holder properly
                this.holder = this.getHolder();
                this.holder.addCallback(this);
                this.holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
        }

        @Override
        public void surfaceCreated(SurfaceHolder holder) 
        {
                try
                {
                        //Open the Camera in preview mode
                        this.camera = Camera.open();
                        this.camera.setPreviewDisplay(this.holder);
                }
                catch(IOException ioe)
                {
                        ioe.printStackTrace(System.out);
                }
        }

        @Override
        public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) 
        {
                // Now that the size is known, set up the camera parameters and begin
                // the preview.
                Camera.Parameters parameters = camera.getParameters();
                parameters.setPreviewSize(width, height);
                camera.setParameters(parameters);
                camera.startPreview();
        }

        @Override
        public void surfaceDestroyed(SurfaceHolder holder) 
        {
                // Surface will be destroyed when replaced with a new screen
                //Always make sure to release the Camera instance
                camera.stopPreview();
                camera.release();
                camera = null;
        }

        public Camera getCamera() {
            return camera;
        }
}

start_camera.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="fill_parent"
    android:layout_height="fill_parent">

    <FrameLayout android:id="@+id/cPreview"
        android:layout_weight="1" android:layout_width="fill_parent"
        android:layout_height="fill_parent">
    </FrameLayout>

</LinearLayout>
like image 381
jvhashe Avatar asked Jul 28 '11 14:07

jvhashe


3 Answers

Apparently this is due to FrameLayout being empty and thus not creating any kind of SurfaceView. You can try to force the parent LinearLayout setting height and width manually or simply adding an imageView inside the FrameLayout. Since FrameLayout may contain many widgets, but it only shows the last of them you can put a ImageView inside the FrameLayout showing a small image only for the SurfaceView to be created.

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="fill_parent"
android:layout_height="fill_parent">

<FrameLayout android:id="@+id/cPreview"
    android:layout_weight="1" android:layout_width="fill_parent"
    android:layout_height="fill_parent">

<!-- Adding small dummy image -->
<ImageView android:layout_width="wrap_content"
    android:layout_height="wrap_content" 
    src="@drawable/small_picture">

</FrameLayout>

</LinearLayout>
like image 92
Ralph Avatar answered Nov 05 '22 17:11

Ralph


I have had the same problem. For me it was because the View size was being set to 0, and therefore the surface was never created. I checked this by setting a specific size, and all of a sudden the callbacks were called. (Same, apparently, holds if the View is laid out off-screen).

like image 30
Greg Bacchus Avatar answered Nov 05 '22 17:11

Greg Bacchus


@jvnane I tried your code, it works, with minor bug.

surfaceChanged is called without problem. In what way you think it doesn't work? Try adding debug message and see it in LogCat:

@Override
public void surfaceCreated(final SurfaceHolder holder)
{
    Log.i("Camera Test", "It works!");
    try
    {
        //Open the Camera in preview mode
        this.camera = Camera.open();
        this.camera.setPreviewDisplay(this.holder);
    }
    catch(final IOException ioe)
    {
        ioe.printStackTrace(System.out);
    }
}

Minor bug: Camera object is released in surfaceDestroyed so you don't need to release it again in the activity's onPause. Also, you need to call super.onPause() when overriding onPause() method.

like image 3
Alan Avatar answered Nov 05 '22 16:11

Alan