No puedo encontrar la causa de mi accidente con este seguimiento de pila

Lo que hace mi aplicación, es mostrar una vista de superposición del sistema adjunta mediante el windowManager.addView() y WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY . Esto se hace con un servicio, que gestiona esa visibilidad de la vista y algunas otras cosas.

Sin embargo, estoy recibiendo informes de fallos y no puedo reproducirlos. También la traza de pila de bloqueo no tiene nada que ver con el paquete de mi aplicación, por lo que realmente no puede obtener la raíz de este problema. Los siguientes son dos stacktraces que provienen de diferentes fuentes, pero parecen estar relacionados:

 java.lang.NullPointerException: Attempt to invoke virtual method 'void android.view.View.measure(int, int)' on a null object reference at android.view.ViewRootImpl.performMeasure(ViewRootImpl.java:2388) at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2101) at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1297) at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:7011) at android.view.Choreographer$CallbackRecord.run(Choreographer.java:777) at android.view.Choreographer.doCallbacks(Choreographer.java:590) at android.view.Choreographer.doFrame(Choreographer.java:560) at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:763) at android.os.Handler.handleCallback(Handler.java:739) at android.os.Handler.dispatchMessage(Handler.java:95) at android.os.Looper.loop(Looper.java:145) at android.app.ActivityThread.main(ActivityThread.java:6938) at java.lang.reflect.Method.invoke(Native Method) at java.lang.reflect.Method.invoke(Method.java:372) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1404) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1199) 

.

 java.lang.NullPointerException: Attempt to invoke virtual method 'int android.view.View.getMeasuredWidth()' on a null object reference at android.view.ViewRootImpl.performLayout(ViewRootImpl.java:2484) at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2181) at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1293) at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6599) at android.view.Choreographer$CallbackRecord.run(Choreographer.java:800) at android.view.Choreographer.doCallbacks(Choreographer.java:603) at android.view.Choreographer.doFrame(Choreographer.java:572) at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:786) at android.os.Handler.handleCallback(Handler.java:815) at android.os.Handler.dispatchMessage(Handler.java:104) at android.os.Looper.loop(Looper.java:194) at android.app.ActivityThread.main(ActivityThread.java:5616) at java.lang.reflect.Method.invoke(Native Method) at java.lang.reflect.Method.invoke(Method.java:372) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:959) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:754) 

Parece que el sistema operativo (ViewRootImpl) está causando este problema, ya que posee una referencia nula a mi vista. Así que no puedo encontrar una solución para esto.

Parece que sucede en todas las versiones de Android desde 4.4 y mi aplicación es Proguarded. Estos rastreos de pila se obtienen de los informes de fallos de Google Play Store

He aquí cómo adjunto vista a la ventana del sistema como una superposición:

 private void attachToSystemWindows(boolean overlayNavigationBar) { final WindowManager windowManager = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE); final DisplayMetrics metrics = new DisplayMetrics(); windowManager.getDefaultDisplay().getMetrics(metrics); final boolean isNavBarInBottom = isNavBarInBottom(); final WindowManager.LayoutParams params = new WindowManager.LayoutParams( calculateWindowWidth(overlayNavigationBar, isNavBarInBottom, metrics, mNavigationBarHeight), calculateWindowHeight(overlayNavigationBar, isNavBarInBottom, metrics, mNavigationBarHeight), 0, 0, WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY, 0x50728, -3 ); params.gravity = Gravity.TOP; windowManager.addView(this, params); } private boolean isNavBarInBottom() { final boolean isLargeDevice = getResources().getConfiguration().smallestScreenWidthDp >= 600; final int orientation = getResources().getConfiguration().orientation; if (BuildConfig.DEBUG) Log.d("MeshView", "Is NavBar in bottom: " + (isLargeDevice || orientation == Configuration.ORIENTATION_PORTRAIT)); return isLargeDevice || orientation == Configuration.ORIENTATION_PORTRAIT; } 

Y mi método onMeasure:

 @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); if (BuildConfig.DEBUG) Log.d("MeshView", "OnMeasure"); setMeasuredDimension( Math.max(getSuggestedMinimumWidth(), resolveSize(SIZE_MIN_WIDTH, widthMeasureSpec)), Math.max(getSuggestedMinimumHeight(), resolveSize(SIZE_MIN_HEIGHT, heightMeasureSpec)) ); } 

Asombroso. Finalmente encontré la raíz de mi problema, pero no la razón … Estaba haciendo algo con mi vista: quería cambiar sus parámetros de diseño dependiendo de su orientación, así que onConfigurationChanged() .

Entonces utilicé una manera repugnante de poner al día los params de la disposición: separar y después fijarla otra vez a WindowManager , apenas como esto:

 @Override protected void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); final ViewGroup.LayoutParams layoutParams = getLayoutParams(); if (!(layoutParams instanceof WindowManager.LayoutParams)) return; //Fix for some ClassCastException in Samsung devices final WindowManager windowManager = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE); final DisplayMetrics metrics = new DisplayMetrics(); windowManager.getDefaultDisplay().getMetrics(metrics); final boolean isNavBarInBottom = isNavBarInBottom(); layoutParams.width = calculateWindowWidth(mOverlayNavigationBar, isNavBarInBottom, metrics, mNavigationBarHeight); layoutParams.height = calculateWindowHeight(mOverlayNavigationBar, isNavBarInBottom, metrics, mNavigationBarHeight); windowManager.removeView(this); windowManager.addView(this, layoutParams); } 

Supongo que algo malo sucede en la clase ViewRootImpl , lo que hace que no maneje el reattach correctamente, causando un error.

Para solucionar esto, sólo tiene que pasar por la forma correcta: Utilice el WindowManager.updateViewLayout(); método:

 @Override protected void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); if (BuildConfig.DEBUG) Log.d("MeshView", "OnConfigurationChanged"); final ViewGroup.LayoutParams layoutParams = getLayoutParams(); if (!(layoutParams instanceof WindowManager.LayoutParams)) return; //Fix for some ClassCastException in Samsung devices final WindowManager windowManager = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE); final DisplayMetrics metrics = new DisplayMetrics(); windowManager.getDefaultDisplay().getMetrics(metrics); final boolean isNavBarInBottom = isNavBarInBottom(); layoutParams.width = calculateWindowWidth(mOverlayNavigationBar, isNavBarInBottom, metrics, mNavigationBarHeight); layoutParams.height = calculateWindowHeight(mOverlayNavigationBar, isNavBarInBottom, metrics, mNavigationBarHeight); //windowManager.removeView(this); DON'T DO THIS //windowManager.addView(this, layoutParams); DON'T DO THIS windowManager.updateViewLayout(this, layoutParams); //DO THIS INSTEAD } 

Esto parece arreglar mi problema. Debo agradecer al autor de este post, que me permitió encontrar esta corrección): Android: cambiar LayoutParams de vista agregado por WindowManager

Creo que no está pasando la bandera correcta al crear params .

 final WindowManager.LayoutParams params = new WindowManager.LayoutParams( calculateWindowWidth(overlayNavigationBar, isNavBarInBottom, metrics, mNavigationBarHeight), calculateWindowHeight(overlayNavigationBar, isNavBarInBottom, metrics, mNavigationBarHeight), 0, 0, WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY, 0x50728, // problem might be here. -3 ); 

Debe ser uno de estos valores .

Así que usa algo como esto (evita pasar valores hexadecimales directamente):

 final WindowManager.LayoutParams params = new WindowManager.LayoutParams( calculateWindowWidth(overlayNavigationBar, isNavBarInBottom, metrics, mNavigationBarHeight), calculateWindowHeight(overlayNavigationBar, isNavBarInBottom, metrics, mNavigationBarHeight), 0, 0, WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY, WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON, //any flag PixelFormat.TRANSLUCENT ); 

También he hecho referencia a PixelFormat .

Trate de cambiar de esta manera y ver si funciona.

Es corto cuando se quita la vista por ( windowManager.removeView(this) ) después de una cadena de llamadas ViewRoot.dispatchDetachedFromWindow () que básicamente establece la vista de viewroot a null que es la razón por la que tiene el NPE mientras está en traversal.

En Detalles: haciendo

windowManager.removeView(this);

Esencialmente llamas die en el ViewRoot de la vista, que luego envía MSG_DIE a su manejador para que mata es más tarde cuando es seguro y agrega la vista a mDyingViews lista en el WindowManagerGlobal. Esto es todo bien,

Sin embargo llamando:

windowManager.addView(this, layoutParams);

Forzar la muerte del ViewRoot y llamar a doDie() y consecutivamente ViewRoot.dispatchDetachedFromWindow() que establece la vista a null mientras está en traversal y tiene NPE.

Para más información, verifique WindowManagerGlobal y ViewRootImpl

Proguard puede causar un problema de Rastreo de la Pila, aunque debería haber habido un indicio de su propio código, aunque una lectura adicional de que necesita descifrar, por lo que esto me toca, apagar Proguard a través de Gradle, a continuación, ejecutar de nuevo y ver.

Tuve el mismo problema en mi aplicación que resolví el problema utilizando

 public static final int TYPE_SYSTEM_ALERT; 

En lugar de TYPE_SYSTEM_OVERLAY. Supongo que la vista ya está destruida antes de llamar onMeasure (). Este tipo de superposición de alguna manera crea un problema en especialmente ningún dispositivo llamado kat pre kits.

Nota: Si desea que su ventana de superposición se muestre detrás de la barra de estado y todavía por encima de todas las otras aplicaciones de uso;

 public static final int TYPE_PHONE; 

Espero que esto ayude.

  • DispatchKeyEvent desde Service
  • Cómo establecer Opacity (Alpha) para ver en Android
  • SetClickable () no funciona en el botón
  • Cómo agregar el evento de botón de clic en el estudio de android
  • Android ignorando mi setWidth () y setHeight ()
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.