【问题标题】:Android camera: stopPreview vs releaseCameraAndroid 相机:stopPreview 与 releaseCamera
【发布时间】:2015-05-11 11:33:11
【问题描述】:

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

  • 进入和退出应用程序:startCamera() & releaseCamera()
  • 标签可见和不可见:startPreview() & stop Preview()

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

【问题讨论】:

    标签: android camera android-camera


    【解决方案1】:

    我也遇到过类似的情况。 :

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

    我想到了两个选择:

    将整个实例转移到不同的线程中

    使用 stopPreview() 和 startPreview()

    我选择了第二个:

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

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

    【讨论】:

    • 关于快速滑动,完全忘记了。 +1
    • 很高兴为您提供帮助。告诉我你用了什么!
    【解决方案2】:

    你好,Karl 我有同样的事情需要在视图寻呼机中实现。我有一个圆形查看器,其中一个片段具有相机片段。我想以这种方式处理相机预览,这样它就不会消耗相机资源。

    如您所知,android view pager 默认将两个片段加载到内存中。我们实现了视图分页器更改监听器并调用片段方法来启动和停止预览。甚至还可以在片段的销毁方法中销毁相机预览。

    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这两个方法,这两个是每个view pager fragment实现的自定义函数。在视图寻呼机更改事件中,我们调用当前片段的暂停和新片段的 onResume。

    // new fragment onResume
     loadedFragment(newPosition).onResumeFragment();
    
     // current fragment onPuase called
     loadedFragment(currentPosition).onPauseFragment();
    

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

    【讨论】:

    • 你让我走上了正确的道路,我有一个非常好的解决方案,我会发布!
    【解决方案3】:

    最好的解决方案是在 onResume() 中 startCamera(),并在 onPause() 中释放它,这样您就可以处理,在 onResume() 中相机不是空闲的。 在 ViewPager 中,您可以 startPreview(),当片段被选中时,或者 stopPreview() 否则。您也可以在片段中的 onCreateView() 中的 startPreview() 和 onDestroyView() 中的 stopPreview()。

    【讨论】:

      【解决方案4】:

      这会处理大部分操作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;
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-07-08
        • 1970-01-01
        相关资源
        最近更新 更多