Después de un tiempo de uso, mi aplicación se congela durante el desplazamiento de un WebView, diciendo "no se pudo bloquear la superficie"

Mi aplicación de Android consta de varias actividades, cada una responsable de un solo fragmento (por ahora). Mis fragmentos se suelen mostrar / adjunto algo así:

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(); } 

El TopicFragment contiene un WebView muestra algunas cosas HTML y CSS / JS. Después de algún tiempo de navegación a través de la aplicación, el desplazamiento en una de estas WebViews TopicFragment vuelve lento y, finalmente, la aplicación se bloquea completamente. El registro ADB muestra la excepción siguiente:

 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) 

En Internet, sólo puedo encontrar información sobre esta excepción, donde las personas tienen sus vistas personalizadas. ¿Qué pasa aquí? ¿Puede estar relacionada con el consumo de memoria de mi aplicación? Parece como si cada vez que llamo el código anterior, un nuevo TopicFragment se instancia, se muestra y se empuja a la pila trasera. ¿Cómo podría depurar más este comportamiento?


Una más información: La aplicación parece utilizar un montón de CPU cuando habilito la superposición en la configuración del desarrollador. ¿Puede ser, que mis fragmentos no están bien separados cuando los dejo y por alguna razón seguir corriendo en el fondo?


Así es como uso el 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); 

No es el escape de memoria mencionado aquí .

Supongo que lo arreglé. Al parecer, hay un error que impide la gestión de memoria correcta de la WebView. Cuando inicio muchas Actividades con WebView en sus vistas, las WebViews viven en la memoria y las actividades no se eliminan correctamente cuando la memoria se agota. He trabajado alrededor del problema con el código siguiente en mi TopicFragment que exhibe el 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(); } 

De esta manera, el WebView se crea y se elimina en onResume y onPause . Esto es algo de sobrecarga y no es perfecto, pero resuelve el problema de memoria y es apenas perceptible en términos de rendimiento y así sucesivamente.

Si tiene varias WebView en su aplicación en diferentes actividades / fragmentos, puede intentar utilizar una agrupación en la que puede recuperar una instancia de WebView en el método Activies onCreate () y devolver la WebView a Pool en Activies onDestory ().

El tamaño de WebViewPool puede ser configurado por la clase de memoria del dispositivo de los usuarios. Esto puede no ser la mejor solución para cada aplicación que utiliza webviews, pero es una solución que puede considerar. Es posible que necesite algunas pruebas, etc.

Pero tenga en cuenta que los objetos en una piscina no se recolectan basura, así que tenga cuidado si decide usar una piscina.

Finalmente encontré el problema. Desactivar la aceleración de hardware para WebView lo resuelve.

 public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle saved) { //... if (Utils.isKitkat()) { disableHardwareAcc(); } //... } @TargetApi(Build.VERSION_CODES.HONEYCOMB) protected void disableHardwareAcc() { mWebView.setLayerType(View.LAYER_TYPE_SOFTWARE, null); } 
  • Android: carga el contenido de la base de datos sqlite en webview
  • Al seleccionar una imagen, la aplicación se reinicia en S3
  • Android PhoneGap obtener guiñada, tono, rollo, relativo a las coordenadas de tierra
  • ¿Cómo escribes y usas correctamente una subclase View en Android?
  • Detectar el cambio de ubicación de la URL de webview de Android
  • Cómo trabajar con ventanas emergentes ventana en android webview
  • Contenido de la web de android no seleccionable
  • Android no puede implementar el comentario de facebook en una vista web debido al navegador predeterminado
  • Vista web de Android Timeout si tarda más de un cierto tiempo en cargar
  • WebView en Android ICS, problemas de iframe con android_assets
  • Desbordamiento de iframe de Webview
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.