android - SurfaceView crashes on orientation change -


i using surfaceview draw on top of camera preview, adapting code this tutorial. app works @ first crashes on orientation change, on first change, after changing 2 or 3 times. i've seen quite few similar questions none has solution (for case). exception:

05-09 22:14:48.384: d/libegl(829): loaded /vendor/lib/egl/libegl_powervr_sgx540_120.so 05-09 22:14:48.400: d/libegl(829): loaded /vendor/lib/egl/libglesv1_cm_powervr_sgx540_120.so 05-09 22:14:48.408: d/libegl(829): loaded /vendor/lib/egl/libglesv2_powervr_sgx540_120.so 05-09 22:14:48.486: d/openglrenderer(829): enabling debug mode 0 05-09 22:14:49.056: i/choreographer(829): skipped 40 frames!  application may doing work on main thread. 05-09 22:14:49.337: d/dalvikvm(829): gc_for_alloc freed 113k, 2% free 8736k/8876k, paused 50ms, total 64ms 05-09 22:14:49.353: i/dalvikvm-heap(829): grow heap (frag case) 11.521mb 3110416-byte allocation [snip lots] 05-09 22:14:56.423: d/androidruntime(829): shutting down vm 05-09 22:14:56.423: w/dalvikvm(829): threadid=1: thread exiting uncaught exception (group=0x4180a930) 05-09 22:14:56.439: e/androidruntime(829): fatal exception: main 05-09 22:14:56.439: e/androidruntime(829): java.lang.runtimeexception: method called after release() 05-09 22:14:56.439: e/androidruntime(829):  @ android.hardware.camera.sethaspreviewcallback(native method) 05-09 22:14:56.439: e/androidruntime(829):  @ android.hardware.camera.access$600(camera.java:131) 05-09 22:14:56.439: e/androidruntime(829):  @ android.hardware.camera$eventhandler.handlemessage(camera.java:784) 05-09 22:14:56.439: e/androidruntime(829):  @ android.os.handler.dispatchmessage(handler.java:99) 05-09 22:14:56.439: e/androidruntime(829):  @ android.os.looper.loop(looper.java:137) 05-09 22:14:56.439: e/androidruntime(829):  @ android.app.activitythread.main(activitythread.java:5041) 05-09 22:14:56.439: e/androidruntime(829):  @ java.lang.reflect.method.invokenative(native method) 05-09 22:14:56.439: e/androidruntime(829):  @ java.lang.reflect.method.invoke(method.java:511) 05-09 22:14:56.439: e/androidruntime(829):  @ com.android.internal.os.zygoteinit$methodandargscaller.run(zygoteinit.java:793) 05-09 22:14:56.439: e/androidruntime(829):  @ com.android.internal.os.zygoteinit.main(zygoteinit.java:560) 05-09 22:14:56.439: e/androidruntime(829):  @ dalvik.system.nativestart.main(native method) 05-09 22:14:58.236: i/process(829): sending signal. pid: 829 sig: 9 

my main activity contains camera preview:

public class mainactivity extends activity implements surfaceholder.callback, locationlistener {  private camera camera; private surfaceview camerasv; private surfaceholder camerash; private overlayview overlay;  /* activity event handlers */ // called when activity initialised os @override public void oncreate(bundle inst) {     super.oncreate(inst);     setcontentview(r.layout.activity_main);     initcamera(); }  // called when activity closed os @override public void ondestroy() {     super.ondestroy();     // turn off camera     stopcamera(); }  /* surfaceholder event handlers */ // called when surface first created public void surfacecreated(surfaceholder holder) { }  // called when surface dimensions etc change public void surfacechanged(surfaceholder sh, int format, int width,         int height) {     // start camera preview     startcamera(sh, width, height); }  // called when surface closed/destroyed public void surfacedestroyed(surfaceholder sh) {     stopcamera(); }  private void initcamera() {     camerasv = (surfaceview) findviewbyid(r.id.surface_camera);     camerash = camerasv.getholder();     camerash.addcallback(this);      camera = camera.open();      overlay = (overlayview) findviewbyid(r.id.surface_overlay);     overlay.getholder().setformat(pixelformat.translucent);     overlay.setcamera(camera); }  // setup camera based on surface parameters private void startcamera(surfaceholder sh, int width, int height) {     camera.parameters p = camera.getparameters();     (camera.size s : p.getsupportedpreviewsizes()) {          p.setpreviewsize(s.width, s.height);         overlay.setpreviewsize(s);         break;     }     if (this.getresources().getconfiguration().orientation != configuration.orientation_landscape) {         // p.set("orientation", "portrait");         // p.setrotation(90);         camera.setdisplayorientation(90);     } else {         // p.set("orientation", "landscape");         // p.setrotation(0);         camera.setdisplayorientation(0);     }     camera.setparameters(p);      try {         camera.setpreviewdisplay(sh);     } catch (exception e) { // log surface setting exceptions      }     camera.startpreview(); }  // stop camera when application ends private void stopcamera() {     if (camerash != null) camerash.removecallback(this);     if (camera != null) {         camera.stoppreview();         camera.release();     } }    } 

my custom surfaceview class drawn on top of camera preview:

public class overlayview extends surfaceview { private surfaceholder surfaceholder; private camera camera; private camera.size framesize;  public overlayview(context ctx) {     super(ctx);     surfaceholder= getholder(); }  public overlayview(context ctx, attributeset attr) {     super(ctx, attr);     surfaceholder = getholder(); }  public void setpreviewsize(camera.size s) {     framesize = s; }  // called initcamera, set callback public void setcamera(camera c) {     camera = c;     camera.setpreviewcallback(new previewcallback() {         // called camera hardware, preview frame         public void onpreviewframe(byte[] frame, camera c) {             canvas canvas = surfaceholder.lockcanvas(null);             canvas.drawcolor( 0, porterduff.mode.clear );             try {                 // perform overlay rendering here                 paint pt = new paint();                 pt.setcolor(color.black);                 pt.settextsize(70);                  canvas.drawtext("hi", 10, framesize.height-10, pt);             } catch (exception e) {                 // log/trap rendering errors             } {                 surfaceholder.unlockcanvasandpost(canvas);             }         }     }); } } 

the layout:

<?xml version="1.0" encoding="utf-8"?> <framelayout xmlns:android="http://schemas.android.com/apk/res/android"   android:orientation="vertical"   android:layout_width="fill_parent"   android:layout_height="fill_parent">      <com.example.overlayview android:id="@+id/surface_overlay"   android:layout_width="fill_parent"   android:layout_height="fill_parent" />      <surfaceview android:id="@+id/surface_camera"   android:layout_width="fill_parent"   android:layout_height="fill_parent" /> </framelayout> 

finally, manifest has these permissions:

<uses-permission android:name="android.permission.internet" /> <uses-permission android:name="android.permission.camera" /> <uses-permission android:name="android.permission.access_fine_location" /> <uses-permission android:name="android.permission.access_coarse_location" /> 

it looks me error arises calling camera.stoppreview() after camera.release() since stopcamera() method being called twice, once in ondestroy() , once again in onsurfacedestroyed(). if set camera , camerash null after respective teardown code, prevent happening. suggested fix in stopcamera():

if (camerash != null) {     camerash.removecallback(this);     camerash = null;  } if (camera != null) {     camera.stoppreview();     camera.release();     camera = null; } 

Comments

Popular posts from this blog

linux - xterm copying to CLIPBOARD using copy-selection causes automatic updating of CLIPBOARD upon mouse selection -

c++ - qgraphicsview horizontal scrolling always has a vertical delta -