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
Post a Comment