Reutilización de objetos de vista de Android: impide que el tamaño antiguo se muestre cuando se vuelve a ver

EDIT: Una pieza más de información posiblemente relevante: El caso de uso en el que veo el problema es conmutación de tabulación. Es decir, creo la vista X en la pestaña A, la elimino al salir de la pestaña A, luego la reciclo en la pestaña B. Ahí es cuando ocurre el problema. Esto también es exactamente cuando necesito la ganancia de rendimiento. . .

Estoy trabajando en el rendimiento de mi aplicación para Android. He notado que puedo acelerar las cosas reutilizando los objetos View de una clase que llamaremos MyLayout. (En realidad, es una subclase personalizada de FrameLayout, pero eso probablemente no importa.También, esto no está relacionado con ListView). Es decir, cuando he terminado con una vista, en lugar de dejar GC obtener ahold de ella, lo pongo en una piscina. Cuando la misma actividad quiere otro objeto MyLayout, tomo uno de la piscina, si está disponible. Esto realmente acelerar la aplicación. Pero estoy teniendo dificultades para borrar la información de tamaño antiguo. El resultado es que cuando agarro la vista atrás, las cosas suelen estar bien, pero en algunos casos, la nueva vista aparece brevemente antes de que se distribuya con la nueva información de tamaño. Esto ocurre aunque establezco nuevos LayoutParams poco antes o después de agregar la Vista de nuevo a la jerarquía (he intentado ambas formas, no ayuda). Así que el usuario ve un flash breve (tal vez 100ms) del tamaño antiguo, antes de que vaya al tamaño correcto.

Me estoy preguntando si / cómo puedo trabajar alrededor de esto. A continuación, a través de C # / Xamarin, hay algunas cosas que he probado, ninguna de las cuales ayuda:

Al reciclar:

//Get myLayoutParams, then: myLayoutParams.Width = 0; myLayoutParams.Height = 0; this.SetMeasuredDimension(0, 0); this.RequestLayout(); 

Inmediatamente antes o después de regresar – dentro del mismo bucle de eventos que agrega el diseño a su nuevo padre:

 // a model object has already computed the desired x, y, width, and height // It's taken into account screen size and the like; the Model's sizes // are definitely what I want. FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams (model.width, model.height); layoutParams.LeftMargin = model.x; layoutParams.TopMargin = model.y; this.LayoutParameters = layoutParams; 

También he intentado traerlo de vuelta como el de abajo, pero el problema sigue siendo:

 FrameLayout.LayoutParams layoutParams = . . . // the same LayoutParams as above parent.AddView(viewThatIsBeingRecycled, layoutParams); 

EDIT: Por solicitud, algunas de las secuencias que he intentado. Todos sufren del mismo problema. La cuestión básica es que, aunque los LayoutParams son correctos, el diseño en sí no es correcto, ya que el diseño actual todavía no ha ocurrido.

Tiempo de reciclaje:

Intento A:

 this.RemoveFromHierarchy(); // problem is that the width and height are retained 

Intento B:

 //Get myLayoutParams, then: myLayoutParams.Width = 0; myLayoutParams.Height = 0; this.SetMeasuredDimension(0, 0); this.RequestLayout(); this.RemoveFromHierarchy(); //problem is that even though layout has been requested, it does not actually happen. //Android seems to decide that since the view is no longer in the hierarchy, //it doesn't need to do the actual layout. So the width and height //remain, just as they do in attempt A above. 

Al agregar la vista de nuevo:

Todos los intentos llaman a una de las siguientes subrutinas para sincronizar LayoutParams con el modelo:

 public static void SyncExistingLayoutParamsToModel(FrameLayout.LayoutParams layoutParams, Model model) { layoutParams.TopMargin = model.X; layoutParams.LeftMargin = model.Y; layoutParams.Width = model.Width; layoutParams.Height = model.Height; } public static FrameLayout.LayoutParams CreateLayoutParamsFromModel(Model model) { FrameLayout.LayoutParams r = new FrameLayout.LayoutParams(model.Width, model.Height); r.LeftMargin = x; r.TopMargin = y; return r; } 

Intento A:

 newParent.AddView(viewThatIsBeingRecycled); // get layoutParams of the view, then: SyncExistingLayoutParamsToModel(myLayoutParams, model); 

Intento B: igual que A, pero en el orden opuesto:

 // get layoutParams of the view, then: SyncExistingLayoutParamsToModel(myLayoutParams, model); newParent.AddView(viewThatIsBeingRecycled); 

Intento C: igual que A, pero con layoutParams nuevo:

 newParent.AddView(viewThatIsBeingRecycled); FrameLayout.LayoutParams layoutParams = CreateLayoutParamsFromModel(model); viewThatIsBeingRecycled.LayoutParams = layoutParams; 

Intento D: igual que B, pero con layoutParams fresco:

 FrameLayout.LayoutParams layoutParams = CreateLayoutParamsFromModel(model); viewThatIsBeingRecycled.LayoutParams = layoutParams; newParent.AddView(viewThatIsBeingRecycled); 

Intento E: usando el AddView que toma un argumento layoutParams:

 FrameLayout.LayoutParams layoutParams = CreateLayoutParamsFromModel(model); newParent.AddView(viewThatIsBeingRecycled, layoutParams); 

En los cinco casos, el problema es que, aunque los layoutParams son correctos, la vista se hace visible al usuario antes de que el diseño se ajuste a los nuevos layoutParams.

Como de costumbre, para actualizar la posición / disposición de cualquier vista, debe ser invalidate ().

No quiero darle forma hackish para pasar, pero todavía quiero que eche un vistazo a este post. Es posible que su requestLayout() no cause la invalidación de View.

También intenta agregar android:hardwareAccelerated="true" en el manifiesto.

Intente ejecutar estos eventos ( setLayoutParams y addView ) en una cola de mensajes.

Solución 1)

 FrameLayout.LayoutParams layoutParams = CreateLayoutParamsFromModel(model); viewThatIsBeingRecycled.setLayoutParams(layoutParams); viewThatIsBeingRecycled.post(new Runnable() { @Override public void run() { newParent.AddView(viewThatIsBeingRecycled); } }); 

Solución 2)

 FrameLayout.LayoutParams layoutParams = CreateLayoutParamsFromModel(model); viewThatIsBeingRecycled.setLayoutParams(layoutParams); viewThatIsBeingRecycled.setVisibility(View.INVISIBLE); newParent.AddView(viewThatIsBeingRecycled); newParent.post(new Runnable() { @Override public void run() { viewThatIsBeingRecycled.setVisibility(View.VISIBLE); } }); 

No estoy seguro de si esto funciona en su caso. Si setLayoutParams o addView se considera un mensaje en la implementación interna del sistema operativo, coloca el siguiente evento en una cola para que se ejecute una vez que se ejecute el evento anterior.

Espero que te ayude:

 view.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { //set layout params here } }); 

Aplicar Gravity con la vista a la que se asocian estos parámetros de diseño

EDITAR

También en tu intento B, en lugar de this.requestLayout(); Llamar a eso en la View padre que será getView() del Fragment o el contenido de la Activity View … Diciendo que el niño a la disposición de sí mismo hace que el padre dirty , por lo que llamará requestLayout() para sí mismo a la distribución, es decir Lo que creo que es la razón de la demora, ya que se ejecutan de una manera sucesiva, pero si lo hacen una llamada directa todo lo que será el diseño universal, lo que eliminará el retraso

Espero eso ayude

Me encontré con el mismo problema excepto en el androide nativo, no xamarin.

Tener mi propia escena de prueba, hizo las cosas mucho más fáciles de depurar el problema. Parece que lo han fijado por el ajuste de derecha e izquierda de la vista específica a 0, justo después de eliminar de su padre y antes de añadir a otro:

 ((ViewGroup)view.getParent()).removeView(view); view.setRight(0); view.setLeft(0); otherLayout.addView(view); 
  • Cómo animar el cambio de un gestor de diseño de la vista de reciclador
  • TextView en el centro de la pantalla
  • Android mover la disposición hasta cuando el teclado suave se muestra con viewpagers
  • WebView con una barra de herramientas plegable? (Diseño del material)
  • Android: windowSoftInputMode = "stateVisible" no funciona
  • Galaxia s4 y tal vez todos los teléfonos HD? Fuera de error de memoria de inflado de diseño
  • Cómo poner 50% de ancho
  • Android search: personalizar el diseño de sugerencias
  • Android - ¿Cómo posicionar la vista fuera de la pantalla?
  • EditText del elemento secundario ExpandableListView no puede mantener el foco
  • Insertar contacto a SIM desde Android
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.