Android Camera: Stoppreview Vs Releasecamera
Solution 1:
I had a similar situation. :
If I kept camera (in ViewPager) in on state, the swipe were clunky and OOM exceptions were frequent.
Two options came in my mind:
shift the entire instance in a different thread
OR
use stopPreview() and startPreview()
I went with the second one :
However, instead of doing this on Fragment lifecycle callbacks I gave a button on the fragment which toggled the preview. Reason being, if user is swiping very fast, you can still receive OOm exception since the preview calls will be queued, especially if there are very few fragments in the viewPager.
In essence Release camera onPause(), acquire camera in onResume() and give a groovy button in fragment which will toggle your Preview on the surface!
Solution 2:
Hello Karl I had the same things need to implement in view pager. I have circular viewer in which one fragment has the camera fragment. I want to handle the camera preview in such a way so it should not consume the camera resource.
As you know android view pager default load two fragment in to the memory. We implemented the view pager change listener and call the fragment method to start and stop the preview. even also destroy the camera preview in on destroy method of fragment.
classViewPagerChangeListenerimplementsViewPager.OnPageChangeListener {
intcurrentPosition= DEFAULT_FRAGMENT;
@OverridepublicvoidonPageScrollStateChanged(int state) {
TimberLogger.d(TAG, "onPageScrollStateChanged");
}
@OverridepublicvoidonPageScrolled(int index, float arg1, int arg2) {
TimberLogger.d(TAG, "onPageScrolled" + index);
}
@OverridepublicvoidonPageSelected(int position) {
mWatchPosition = position;
TimberLogger.d(TAG, "onPageSelected" + mWatchPosition);
intnewPosition=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);
}
}
See the two method onResumeFragment and onPuaseFragment this two are the custom function each view pager fragment implements. In view pager change event we call the pause of current fragment and onResume of the new fragment.
// new fragment onResumeloadedFragment(newPosition).onResumeFragment();
// current fragment onPuase calledloadedFragment(currentPosition).onPauseFragment();
You can write your camera start preview inside custom method onResumeFragment and stop preview in onPauseFragment and also make sure you should override the onDestory() method of your camera fragment for release the camera resources.
Solution 3:
The best solution will be to startCamera() in onResume(), and release it in onPause(), so you can handle, that camera is not free in onResume(). In ViewPager you can startPreview(), when fragment with it is selected, and stopPreview() otherwise. Also u can startPreview() in onCreateView() and stopPreview() in onDestroyView() in fragment.
Solution 4:
This takes care of most of the operations 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;
publicclassCameraPreviewextendsSurfaceViewimplementsSurfaceHolder.Callback {
private SurfaceHolder holder;
private Camera camera;
privateint cameraId;
private Activity activity;
private CameraPreviewActivityInterface activityInterface;
publicCameraPreview(Activity activity, int cameraId) {
super(activity);
try {
activityInterface = (CameraPreviewActivityInterface) activity;
} catch (ClassCastException e) {
thrownewClassCastException(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);
}
publicvoidsurfaceCreated(SurfaceHolder holder) {}
/**
* custom camera tweaks and startPreview()
*/publicvoidrefreshCamera() {
if (holder.getSurface() == null || camera == null) {
// preview surface does not exist, camera not opened created yetreturn;
}
Log.i(null, "CameraPreview refreshCamera()");
// stop preview before making changestry {
camera.stopPreview();
} catch (Exception e) {
// ignore: tried to stop a non-existent preview
}
introtation= ((WindowManager) activity.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getRotation();
intdegrees=0;
// specifically for back facing cameraswitch (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());
}
}
publicvoidsurfaceChanged(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 visibleif(activityInterface.getCurrentPage() == 1)
startCamera();
}
@OverridepublicvoidsurfaceDestroyed(SurfaceHolder holder) {}
public Camera getCameraInstance() {
Cameracamera= Camera.open();
// parameters for cameraParametersparams= 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();
intmax=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(newErrorCallback() {
@OverridepublicvoidonError(int error, Camera camera) {
if(error == Camera.CAMERA_ERROR_SERVER_DIED) {
releaseCamera();
startCamera();
}
}
});
return camera;
}
/**
* intitialize a new camera
*/protectedvoidstartCamera() {
if(getCamera() == null)
setCamera(getCameraInstance());
refreshCamera();
}
/**
* release camera so other applications can utilize the camera
*/protectedvoidreleaseCamera() {
// if already null then the camera has already been released beforeif (getCamera() != null) {
getCamera().release();
setCamera(null);
}
}
public Camera getCamera() {
return camera;
}
publicvoidsetCamera(Camera camera) {
this.camera = camera;
}
publicvoidsetCameraId(int cameraId) {
this.cameraId = cameraId;
}
/**
* get the current viewPager page
*/publicinterfaceCameraPreviewActivityInterface {
publicintgetCurrentPage();
}
}
In my FragmentCamera.java
file:
privateCameraPreview cameraPreview;
// code...publicViewonCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// code...
cameraPreview = newCameraPreview(getActivity(), cameraId);
previewLayout.addView(cameraPreview);
// code...
}
// code...@OverridepublicvoidonPause() {
super.onPause();
cameraPreview.releaseCamera();
}
@OverridepublicvoidonResume() {
super.onResume();
cameraPreview.startCamera();
}
protectedvoidfragmentVisible() {
onResume();
}
protectedvoidfragmentNotVisible() {
onPause();
}
And the MainActivity.java file (implements CameraPreviewActivityInterface):
viewPager.setOnPageChangeListener(newOnPageChangeListener() {
@OverridepublicvoidonPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@OverridepublicvoidonPageSelected(int position) {
currentPage = position;
if (currentPage == 1) {
fragmentCamera.fragmentVisible();
} else {
fragmentCamera.fragmentNotVisible();
}
}
@OverridepublicvoidonPageScrollStateChanged(int state) {
}
});
@OverridepublicintgetCurrentPage() {
return currentPage;
}
Post a Comment for "Android Camera: Stoppreview Vs Releasecamera"