Android相机:stopPreview vs releaseCamera

时间:2015-05-11 11:33:12

标签: android camera android-camera

我正在创建一个应用程序,我在viewPager中有一个摄像头。我想知道什么是最适合“暂停”和“恢复”相机,以便它在预加载时不会占用资源。我觉得stopPreview更适合这个,因为它不会释放相机但保留它但是它不显示相机,这是它占用资源的主要原因。

  • 输入&退出应用程序:startCamera()& releaseCamera()
  • 标签可见&不可见:startPreview()&停止预览()

这是一个很好的经验法则吗?

4 个答案:

答案 0 :(得分:1)

我有类似的情况。 :

如果我将相机(在ViewPager中)保持在打开状态,则滑动很笨重,并且OOM异常频繁。

我想到了两个选择:

将整个实例移到另一个线程

OR

使用stopPreview()和startPreview()

我选择了第二个:

然而,我没有在Fragment生命周期回调中执行此操作,而是在片段上提供了一个切换预览的按钮。原因是,如果用户快速刷卡,您仍然可以收到OOm异常,因为预览调用将排队,尤其是如果viewPager中的片段非常少。

实质上释放相机onPause(),在onResume()中获取相机并在片段中提供一个groovy按钮,它将在表面上切换预览!

答案 1 :(得分:1)

Hello Karl我有同样的事情需要在视图寻呼机中实现。我有一个圆形查看器,其中一个片段有相机片段。我希望以这种方式处理相机预览,因此它不应占用相机资源。

如你所知,android view pager默认将两个片段加载到内存中。我们实现了view pager change listener并调用fragment方法来启动和停止预览。甚至还破坏了碎片破坏方法中的相机预览。

class ViewPagerChangeListener implements ViewPager.OnPageChangeListener {

        int currentPosition = DEFAULT_FRAGMENT;

        @Override
        public void onPageScrollStateChanged(int state) {
            TimberLogger.d(TAG, "onPageScrollStateChanged");
        }

        @Override
        public void onPageScrolled(int index, float arg1, int arg2) {
            TimberLogger.d(TAG, "onPageScrolled" + index);
        }

        @Override
        public void onPageSelected(int position) {
            mWatchPosition = position;
            TimberLogger.d(TAG, "onPageSelected" + mWatchPosition);

            int newPosition = 0;
            if (position > 4) {
                newPosition = position;
            }

            TimberLogger.d(TAG, "newPosition" + newPosition);

            /**
             * Listener knows the new position and can call the interface method
             * on new Fragment with the help of PagerAdapter. We can here call
             * onResumeFragment() for new fragment and onPauseFragment() on the
             * current one.
             */

            // new fragment onResume
            loadedFragment(newPosition).onResumeFragment();

            // current fragment onPuase called
            loadedFragment(currentPosition).onPauseFragment();

            currentPosition = newPosition;

            TimberLogger.d(TAG, "currentPosition" + currentPosition);
        }
    }

请参阅两个方法onResumeFragment和onPuaseFragment这两个是每个视图分页器片段实现的自定义函数。在视图寻呼机更改事件中,我们调用当前片段的暂停和新片段的onResume。

// new fragment onResume
 loadedFragment(newPosition).onResumeFragment();

 // current fragment onPuase called
 loadedFragment(currentPosition).onPauseFragment();

您可以在自定义方法onResumeFragment中编写相机开始预览,并在onPauseFragment中停止预览,并确保应覆盖相机片段的onDestory()方法以释放相机资源。

答案 2 :(得分:0)

最好的解决方案是onResume()中的startCamera(),并在onPause()中释放它,这样你就可以处理,onResume()中的相机不是免费的。 在ViewPager中,如果选择了包含它的片段,则可以使用startPreview(),否则使用stopPreview()。你也可以在onCreateView()中的startPreview()和片段中onDestroyView()的stopPreview()。

答案 3 :(得分:0)

这会处理大部分操作CameraPreview.java

package com.example.fela;

import android.app.Activity;
import android.content.Context;
import android.graphics.PixelFormat;
import android.hardware.Camera;
import android.hardware.Camera.ErrorCallback;
import android.hardware.Camera.Parameters;
import android.hardware.Camera.Size;
import android.util.Log;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.WindowManager;

import java.util.List;

public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {

    private SurfaceHolder holder;
    private Camera camera;
    private int cameraId;
    private Activity activity;
    private CameraPreviewActivityInterface activityInterface;

    public CameraPreview(Activity activity, int cameraId) {
        super(activity);
        try {
            activityInterface = (CameraPreviewActivityInterface) activity;
        } catch (ClassCastException e) {
            throw new ClassCastException(activity.toString() + " must implement ExampleFragmentCallbackInterface ");
        }
        this.activity = activity;
        this.cameraId = cameraId;
        holder = getHolder();
        holder.addCallback(this);
        // deprecated setting, but required on Android versions prior to 3.0
        holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    }

    public void surfaceCreated(SurfaceHolder holder) {}

    /**
     * custom camera tweaks and startPreview()
     */
    public void refreshCamera() {
        if (holder.getSurface() == null || camera == null) {
            // preview surface does not exist, camera not opened created yet
            return;
        }
        Log.i(null, "CameraPreview refreshCamera()");
        // stop preview before making changes
        try {
            camera.stopPreview();
        } catch (Exception e) {
            // ignore: tried to stop a non-existent preview
        }
        int rotation = ((WindowManager) activity.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getRotation();
        int degrees = 0;
        // specifically for back facing camera
        switch (rotation) {
            case Surface.ROTATION_0:
                degrees = 90;
                break;
            case Surface.ROTATION_90:
                degrees = 0;
                break;
            case Surface.ROTATION_180:
                degrees = 270;
                break;
            case Surface.ROTATION_270:
                degrees = 180;
                break;
        }
        camera.setDisplayOrientation(degrees);
        setCamera(camera);
        try {
            camera.setPreviewDisplay(holder);
            camera.startPreview();
        } catch (Exception e) {
            // this error is fixed in the camera Error Callback (Error 100)
            Log.d(VIEW_LOG_TAG, "Error starting camera preview: " + e.getMessage());
        }
    }



    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
        Log.i(null, "CameraPreview surfaceChanged()");
        // if your preview can change or rotate, take care of those events here.
        // make sure to stop the preview before resizing or reformatting it.
        // do not start the camera if the tab isn't visible
        if(activityInterface.getCurrentPage() == 1)
            startCamera();
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {}

    public Camera getCameraInstance() {
        Camera camera = Camera.open();
        // parameters for camera
        Parameters params = camera.getParameters();
        params.set("jpeg-quality", 100);
        params.set("iso", "auto");
        params.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
        params.setPictureFormat(PixelFormat.JPEG);
        // set the image dimensions
        List<Size> sizes = params.getSupportedPictureSizes();
        int max = 0, width = 0, height = 0;
        for(Size size : sizes) {
            if(max < (size.width*size.height)) {
                max = (size.width*size.height);
                width = size.width;
                height = size.height;
            }
        }
        params.setPictureSize(width, height);
        camera.setParameters(params);
        // primarily used to fix Error 100
        camera.setErrorCallback(new ErrorCallback() {
            @Override
            public void onError(int error, Camera camera) {
                if(error == Camera.CAMERA_ERROR_SERVER_DIED) {
                    releaseCamera();
                    startCamera();
                }
            }
        });
        return camera;
    }

    /**
     * intitialize a new camera
     */
    protected void startCamera() {
        if(getCamera() == null)
            setCamera(getCameraInstance());
        refreshCamera();
    }

    /**
     * release camera so other applications can utilize the camera
     */
    protected void releaseCamera() {
        // if already null then the camera has already been released before
        if (getCamera() != null) {
            getCamera().release();
            setCamera(null);
        }
    }

    public Camera getCamera() {
        return camera;
    }

    public void setCamera(Camera camera) {
        this.camera = camera;
    }

    public void setCameraId(int cameraId) {
        this.cameraId = cameraId;
    }

    /**
     * get the current viewPager page
     */
    public interface CameraPreviewActivityInterface {
        public int getCurrentPage();
    }
}

在我的FragmentCamera.java文件中:

private CameraPreview cameraPreview;

// code...

public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    // code...
    cameraPreview = new CameraPreview(getActivity(), cameraId);
    previewLayout.addView(cameraPreview);
    // code...
}

// code...

@Override
public void onPause() {
    super.onPause();
    cameraPreview.releaseCamera();
}

@Override
public void onResume() {
    super.onResume();
    cameraPreview.startCamera();
}

protected void fragmentVisible() {
    onResume();
}

protected void fragmentNotVisible() {
    onPause();
}

MainActivity.java文件(实现CameraPreviewActivityInterface):

viewPager.setOnPageChangeListener(new OnPageChangeListener() {
    @Override
    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
    }
    @Override
    public void onPageSelected(int position) {
        currentPage = position;
        if (currentPage == 1) {
            fragmentCamera.fragmentVisible();
        } else {
            fragmentCamera.fragmentNotVisible();
        }
    }
    @Override
    public void onPageScrollStateChanged(int state) {
    }
});

@Override
public int getCurrentPage() {
    return currentPage;
}