Join FlipAndroid.COM Telegram Group: https://t.me/joinchat/F_aqThGkhwcLzmI49vKAiw


Presentación de hardware WebView de Android Problema de artefacto extraño

En algunos dispositivos como el Nexus 7 o Samsung Galaxy Nexus (posiblemente otros), me di cuenta de este problema (ver foto). Esto se ejecuta en modo de aceleración de hardware en un WebView. Sin embargo, cuando lo convierto en modo de renderizado de software, muestra bien, pero ralentiza el rendimiento un poco. Me encantaría saber cómo solucionar este problema y sólo usar la aceleración de hardware en el WebViews y no modo de software.

Mala interpretación (en funcionamiento en el Samsung Galaxy Nexus): Imagen que muestra el problema desgarrador extraño.

Representación correcta (en ejecución en Motorola Bionic): Cómo se debe hacer.

Manifiesto de Android:

<uses-sdk android:minSdkVersion="10" android:targetSdkVersion="17" /> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <supports-screens android:resizeable="true" android:smallScreens="true" android:normalScreens="true" android:largeScreens="true" android:xlargeScreens="true" android:anyDensity="true" /> <application android:allowBackup="true" android:hardwareAccelerated="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > .... </application> </manifest> 

Código Java:

 .... @TargetApi(VERSION_CODES.HONEYCOMB) @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); try{ db = new DatabaseHandler(this); tts = new TextToSpeech(this, this); handler = new Handler(); frame = new FrameLayout(this); frame.setBackgroundColor(Color.GRAY); wv = new WebView(this); wv.setScrollBarStyle(WebView.SCROLLBARS_INSIDE_OVERLAY); frame.addView(wv); wv.setVisibility(WebView.INVISIBLE); iv = new ImageView(this); Drawable d = Drawable.createFromStream(getAssets().open("www/img/loading.jpg"), null); iv.setImageDrawable(d); FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT); iv.setLayoutParams(params); frame.addView(iv); WebSettings ws = wv.getSettings(); ws.setRenderPriority(RenderPriority.HIGH); ws.setJavaScriptEnabled(true); ws.setAllowFileAccess(true); if (Build.VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN) ws.setAllowUniversalAccessFromFileURLs(true); ws.setCacheMode(WebSettings.LOAD_NO_CACHE); SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(this); if(Build.VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB && !pref.getBoolean("prefHardware", true)){ wv.setLayerType(View.LAYER_TYPE_SOFTWARE, null); } wv.setWebChromeClient(new WebChromeClient(){ //int id = 0; @Override public boolean onConsoleMessage(ConsoleMessage consoleMessage) { // TODO Auto-generated method stub // Log.d("JS Console", consoleMessage.message() + " at " + consoleMessage.sourceId() + ":" + consoleMessage.lineNumber()); //Toast.makeText(TaskRunner.this, consoleMessage.message() + " at " + consoleMessage.sourceId() + ":" + consoleMessage.lineNumber(), Toast.LENGTH_LONG).show(); // NotificationCompat.Builder mBuilder = // new NotificationCompat.Builder(TaskRunner.this) // .setSmallIcon(R.drawable.ic_launcher) // .setContentTitle("Console Message") // .setContentText(consoleMessage.message() + " at " + consoleMessage.sourceId() + ":" + consoleMessage.lineNumber()); //// mBuilder.setContentIntent(null); // NotificationManager mNotificationManager = // (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); // // mId allows you to update the notification later on. // mNotificationManager.notify(id++, mBuilder.build()); return super.onConsoleMessage(consoleMessage); } }); wv.setWebViewClient(new WebViewClient(){ @Override public void onPageFinished(WebView view, String url) { // TODO Auto-generated method stub //Log.i("TEST", "TEST"); //hideLoading(); super.onPageFinished(view, url); } @Override public void onPageStarted(WebView view, String url, Bitmap favicon) { // TODO Auto-generated method stub if(frame.getChildAt(frame.getChildCount()-1) != iv){ frame.addView(iv); wv.setVisibility(WebView.INVISIBLE); } super.onPageStarted(view, url, favicon); } @Override public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) { // TODO Auto-generated method stub Log.e("ERROR", description); super.onReceivedError(view, errorCode, description, failingUrl); } }); MyJavascriptInterface ji = new MyJavascriptInterface(); wv.addJavascriptInterface(ji, "ji"); setOrientation(); wv.loadUrl("file:///android_asset/www/index.html"); setContentView(frame); } catch(Exception e){ } } .... 

Archivo HTML:

 <!DOCTYPE html> <html> <head> <title>Task Player</title> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <meta name="format-detection" content="telephone=no" /> ...... </head> <body> <div id="gamespacer"> <div id="instructions-block"> <div id="explaination"> </div> <div id="instructions-close"> <br /><br /> <div class="btn btn-large btn-info" id="speak-tts">Speak</div> <br /><br /> <input type='checkbox' id='auto-speak' value="yes" checked="checked" />Auto speak </div> <div id="drag-container"> <div id='drag'> <span id='au'><img src="img/arrow-up.png" alt="" width="45" /></span> <span id='ad'><img src="img/arrow-down.png" alt="" width="45"/></span> </div> </div> </div> </div> <div id="play-container"> <canvas> </canvas> </div> <div class="centerMe" id="rotate" style="display: none;"><p style="font-size: 24px; margin-top: 20px">Rotate the device to play the game.</p></div> <div id="winScreen"> <div id="points"> You Got<br/> <div id="mypoints">0</div> Points </div> <a href="#" id='done' class="btn btn-large btn-inverse">Done</a> </div> .... </body> </html> 

Css

 #winScreen{ display: none; width: 100%; height: 100%; text-align: center; background-color: green; font-size: 24px; margin: 0 auto; position: absolute; left: 0px; top: 0px; } #points { padding-top: 110px; color: yellow; margin-bottom: 10px; } #mypoints{ margin: 10px; } .button{ margin: 0 auto; margin-top: 50px; } #play-container{ width: 100%; height: 100%; margin: 0 auto; text-align: center; } canvas { background-color: white; position: absolute; top: 0px; left: 0px; } #gamespacer { } #instructions-block { position: absolute; left: 0px; top: -144px; width: 100%; background-color: white; z-index: 1; } #instructions-content { margin-top: 5px; } #instructions-close { text-align: center; margin-bottom: 10px; } #explaination { margin: 5px; font-size: 24px; line-height: 1; position: relative; width: 100% height: 100% } #drag-container{ width: 100%; } #drag { position: absolute; left: 92%; margin-top: 5px; } #au{ display: none; pointer-events: none; } #ad { pointer-events: none; } body{ -webkit-user-select: none; user-select: none; -webkit-touch-callout: none; touch-callout: none; -webkit-tap-highlight-color: rgba(0,0,0,0); tap-highlight-color: rgba(0,0,0,0); } 

ACTUALIZACIÓN 1

Así que probé el código siguiente y que no funcionó tan bien.

 wv.setLayerType(View.LAYER_TYPE_HARDWARE, null); 

ACTUALIZAR 2

Parece como hasta ahora a mi conocimiento que esto sólo sucede en Google hizo dispositivos (como el Nexus). Por lo tanto, ¿podría haber un error en su kernel o controlador de vídeo? O, podría ser algo malo con Android 4.2.2.

Si usted tiene alguna idea sobre cómo arreglar esto, por favor hágamelo saber.

ACTUALIZACIÓN 3

He hecho un proyecto de prueba para que lo pruebes. Jugar con el nivel de zoom y mover la ventana alrededor. Hazme saber si hace algo raro. Hasta ahora lo hace con Android 4.2.2

Http://jsbin.com/equtoq/2

¡Gracias!

  • WebView y HTML5 <video>
  • HTML5 <audio> etiqueta que no funciona en Android Webview
  • PhoneGap - JSON Almacenamiento de datos localmente en el dispositivo
  • ¿La mejor manera de hacer aplicaciones multiplataforma?
  • Android: "No se pudo ejecutar 'reproducir' en 'HTMLMediaElement': la API sólo puede iniciarse con un gesto del usuario
  • Gotchas / errores en el desarrollo de WebKit en iOS o Android
  • Mp4 vídeo en html5 etiqueta de vídeo no se reproduce en el cromo móvil y safari móvil
  • Impactos de rendimiento de Cordova / PhoneGap?
  • 4 Solutions collect form web for “Presentación de hardware WebView de Android Problema de artefacto extraño”

    Después de un número de comienzos falsos, sólo pude encontrar la solución hackish de conmutar entre renderizado de hardware y renderizado de software dependiendo de la escala actual.

    Básicamente, la idea es que los artefactos de representación sólo se mostrarán después de una cierta escala, por lo que podemos utilizar con seguridad el procesamiento de hardware antes de que este umbral se cruce y cambiar a un procesamiento de software más lento pero correcto cuando se utiliza escala mayor. El umbral de escala es> 1.67 en N7, aunque es posible que tenga que comprobar en Galaxy Nexus para ver si este valor es universal. En mi experiencia hay una gran cantidad de problemas con WebView en todas las versiones de Android, por lo que esta puede ser la mejor solución actual hasta que todo el mundo actualiza a 4.3 …

      webView.setWebViewClient(new WebViewClient() { @Override public void onScaleChanged(WebView view, float oldScale, float newScale) { //4.3 SDK required, or change Build.VERSION_CODES.JELLY_BEAN_MR2 to 18 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) { if (newScale > 1.7f) { if (webView.getLayerType() != View.LAYER_TYPE_SOFTWARE) { webView.setLayerType(View.LAYER_TYPE_SOFTWARE, null); } } else { if (webView.getLayerType() != View.LAYER_TYPE_HARDWARE) { webView.setLayerType(View.LAYER_TYPE_HARDWARE, null); } } } } }); 

    Tenga en cuenta que onScaleChanged() se llamaría varias veces, a veces se cruza el umbral con un solo zoom (con el botón de zoom in / out), por lo que debería agregar algo de lógica para reducir el número de llamadas webView.setLayerType () Zoom para reducir los artefactos de renderizado de hardware / software que se mostrarían durante un breve intervalo

    Gracias a Delyan por resolver el problema. Cómo me dijo que lo solucionara era añadir -webkit-transform: translate3d(0,0,0) a todas las partes que se mueven.

    KUDOS DELYAN!

    Asegúrese de acelerar el hardware activado en su XML de manifiesto.

     <application android:hardwareAccelerated="true" ... /> 

    Este es un error de condición de carrera en WebView. Donde la representación de la página no está sincronizada con la vista real de la página.

    La causa normal es porque estás manejando la rotación con android:configChanges en tu etiqueta <activity> en el archivo AndroidManifest.xml . Recrear el WebView en rotación resolverá este problema, pero este mismo tiene otros problemas asociados a él.

    Son dos soluciones que conozco. Yo no recomendaría que siga utilizando android:configChanges como su generalmente perjudicial si realmente no sabe lo que este cambio significa para su aplicación. Si es absolutamente necesario mantener el android:configChanges , hay una solución. Puede crear su propia View personalizada que hereda de un WebView . Basta con anular onConfigurationChanged y no reenviarlo a la clase super .. en este caso, que es el WebView . He incluido el código a continuación como un ejemplo de esto.

    Pero el enfoque más verdadero y correcto es corregir el manejo del ahorro y restauración del estado de WebView. Si usted caza alrededor en línea usted encontrará una multiplicidad de soluciones para este problema. Aquí hay una muy buena. http://www.devahead.com/blog/2012/01/preserving-the-state-of-an-android-webview-on-screen-orientation-change/

     import android.content.Context; import android.content.res.Configuration; import android.util.AttributeSet; import android.webkit.WebView; public class MyWebView extends WebView { public MyWebView(Context context) { super(context); } public MyWebView(Context context, AttributeSet attrs) { super(context, attrs); } public MyWebView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } @Override protected void onConfigurationChanged(Configuration newConfig) { // NOTE: We don't want to call this // super.onConfigurationChanged(newConfig); } } 
    FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.