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:
- WebRTC llega a Android WebView? ¿Cuando?
- Android - Webview, cuadros de entrada dobló?
- Inserte instagram en Android WebView
- 'Webpage not available' con WebView.loadData () SOLAMENTE en el emulador
- Android WebView no cargar contenido mixto
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í .
- Vista web de Android y localStorage
- Recuperar User-Agent mediante programación
- ShouldOverrideUrlLoading se llama SOLAMENTE para ALGUNAS páginas web
- ¿Cuál es el archivo html más grande que se puede cargar en un WebView de Android?
- La descarga de WebView abre la ventana del navegador por un breve momento antes de volver a WebView
- Android - WebView no reproduce videos de YouTube
- Cómo encajar una página web en la pantalla de Android (webview)?
- Enviar solicitud de envío junto con HttpHeaders en Android
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); }
- Haga clic en la mitad superior de un botón – no funciona?
- Ofuscando múltiples módulos con el estudio de Android