My Android app consists of several activities, each responsible for a single fragment (for now). My fragments are usually displayed/attached somewhat like this:
mTopicFragment = (TopicFragment)getSupportFragmentManager().findFragmentByTag("topic");
if(mTopicFragment == null)
mTopicFragment = TopicFragment.newInstance(bid, page, pid);
if (savedInstanceState == null) {
getSupportFragmentManager().beginTransaction()
.add(R.id.content, mTopicFragment, "topic")
.commit();
}
The TopicFragment
contains a WebView
displaying some HTML and CSS/JS stuff. After some time of browsing through the app, the scrolling in one of these TopicFragment
WebViews becomes slow and eventually, the App freezes completely. The ADB log shows the following exception:
12-12 22:49:33.931 12582-12582/com.mde.potdroid3 W/Adreno-EGLSUB﹕ <DequeueBuffer:606>: dequeue native buffer fail: Unknown error 2147483646, buffer=0x0, handle=0x0
12-12 22:49:33.941 12582-12582/com.mde.potdroid3 W/Adreno-EGLSUB﹕ <DequeueBuffer:606>: dequeue native buffer fail: Invalid argument, buffer=0x0, handle=0x0
12-12 22:49:33.941 12582-12582/com.mde.potdroid3 W/Adreno-ES20﹕ <gl2_surface_swap:43>: GL_OUT_OF_MEMORY
12-12 22:49:33.941 12582-12582/com.mde.potdroid3 W/Adreno-EGL﹕ <qeglDrvAPI_eglSwapBuffers:3597>: EGL_BAD_SURFACE
12-12 22:49:33.941 12582-12582/com.mde.potdroid3 W/HardwareRenderer﹕ EGL error: EGL_BAD_SURFACE
12-12 22:49:33.951 12582-12582/com.mde.potdroid3 W/HardwareRenderer﹕ Mountain View, we've had a problem here. Switching back to software rendering.
12-12 22:20:04.461 10081-10081/com.mde.potdroid3 E/Surface﹕ dequeueBuffer failed (Unknown error 2147483646)
12-12 22:20:04.461 10081-10081/com.mde.potdroid3 E/ViewRootImpl﹕ Could not lock surface
java.lang.IllegalArgumentException
at android.view.Surface.nativeLockCanvas(Native Method)
at android.view.Surface.lockCanvas(Surface.java:243)
at android.view.ViewRootImpl.drawSoftware(ViewRootImpl.java:2435)
at android.view.ViewRootImpl.draw(ViewRootImpl.java:2409)
at android.view.ViewRootImpl.performDraw(ViewRootImpl.java:2253)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1883)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1000)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:5670)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:761)
at android.view.Choreographer.doCallbacks(Choreographer.java:574)
at android.view.Choreographer.doFrame(Choreographer.java:544)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:747)
at android.os.Handler.handleCallback(Handler.java:733)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:136)
at android.app.ActivityThread.main(ActivityThread.java:5081)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:781)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
On the internet, I can only find information regarding this Exception, where People have their custom Views. What happens here? Can it be related to memory consumption of my app? It appears as if each time I call the code above, a new TopicFragment
is instantiated, displayed and pushed to the back stack. How could I further debug this behaviour?
One more info: The App seems to use a LOT of CPU when I enable the overlay in the developer settings. May it be, that my fragments are not properly detached when I leave them and for some reason keep running in the background?
This is how I use the WebView:
mWebView = (WebView)getView().findViewById(R.id.topic_webview);
mWebView.getSettings().setJavaScriptEnabled(true);
mWebView.getSettings().setDomStorageEnabled(true);
mWebView.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE);
mWebView.getSettings().setAllowFileAccess(true);
mWebView.addJavascriptInterface(mJsInterface, "api");
mWebView.setWebChromeClient(new WebChromeClient());
mWebView.loadData("", "text/html", "utf-8");
mWebView.setBackgroundColor(0x00000000);
It is not the memory leak mentioned here.
I guess I fixed it. Apparently, there is a bug which prevents correct memory managment of the WebView. When I start many Activities with WebView
in their views, the WebViews live in the memory and the activities are not properly killed when memory runs low. I worked around the issue with the following code in my TopicFragment
which displays the WebView
:
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle saved) {
View v = super.onCreateView(inflater, container, saved);
mActivity = (BaseActivity) getSupportActivity();
// this is the framelayout which will contain our WebView
mWebContainer = (FrameLayout) v.findViewById(R.id.web_container);
return v;
}
public void onResume() {
super.onResume();
// create new WebView and set all its options.
mWebView = new WebView(mActivity);
mWebView....
// add it to the container
mWebContainer.addView(mWebView);
// if data is available, display it immediately
if(mTopic != null) {
mWebView.loadDataWithBaseURL("file:///android_asset/", mTopic.getHtmlCache(),
"text/html", "UTF-8", null);
}
}
@Override
public void onPause() {
super.onPause();
// destroy the webview
mWebView.destroy();
mWebView = null;
// remove the view from the container.
mWebContainer.removeAllViews();
}
This way, the WebView
is created and removed in onResume
and onPause
. This is some overhead and not perfect, but it solves the memory issue and is barely noticable in terms of performance and so on.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With