studio propiedades personalizado gridlayout descargar columnas android android-view android-gridview

android - propiedades - En el adaptador de gridview, se invocó getView(posición== 0) demasiadas veces para medir el diseño cuando setImageBitmap() en un cargador



menu gridview android (4)

Tengo un GridView para mostrar algunos iconos.

ANTES de haber leído esto Mostrando mapas de bits de manera eficiente desde el sitio del desarrollador de Android, estaba descodificando el mapa de bits de la ruta local directamente en getView() del adaptador, como esto:

public View getView(int position, View convertView, ViewGroup parent) { ... ImageView icon = ...... (from getTag() of convertView) icon.setImageBitmap(BitmapUtil.decode(iconPath)); ... }

esta forma funciona bien de todos modos, lo llamé [Modo directo], el registro de salida para el método getView() debería ser:

getView(0) // measure kid''s layout. getView(0) getView(1) getView(2) ... getView(n) // when scrolling gridview. getView(n+1) ... getView(n+3) // scrolling again. getView(n+4) ...

luego estoy tratando de cambiar el código a [Modo cargador] mencionado en el artículo Visualización de mapas de bits de manera eficiente , de la siguiente manera:

public View getView(int position, View convertView, ViewGroup parent) { ... ImageView icon = ...... (from getTag() of convertView) loadIcon(icon, iconPath); ... }

en loadIcon() :

... final CacheImageLoader loader = new CacheImageLoader(getActivity(), imageView, imageUrl, savePath); final AsyncDrawable asyncDrawable = new AsyncDrawable(getResources(), placeHolderBitmap, loader); imageView.setImageDrawable(asyncDrawable);

en el oyente del cargador:

@Override public void onLoadComplete(Loader<Bitmap> arg0, Bitmap arg1) { ... ImageView imageView = imageViewReference.get(); if (result != null && imageView != null) { imageView.setImageBitmap(result); } }

Básicamente, es igual que el código de entrenamiento, en realidad, de esta manera también funciona bien. Sin embargo, encontré algo diferente, en este modo el método getView() en el adaptador se invocó demasiadas veces, sin embargo, estas llamadas repetidas a este método siempre con el parámetro "posición" == 0, significa algo invocar g etView(0, X, X) repetidamente.

getView(0) // measure kid''s layout. getView(0) getView(1) getView(2) ... getView(0) // loader completed then imageView.setImageBitmap(result); getView(0) // same as above getView(0) getView(0) ... getView(n) // when scrolling gridview. getView(n+1) getView(n+2) getView(0) // loader completed then imageView.setImageBitmap(result); getView(0) // same as above getView(0) ... getView(n+3) // scrolling again. getView(n+4) getView(0) // loader completed then imageView.setImageBitmap(result); getView(0) // same as above getView(0)

No es bueno porque estoy usando un cargador en getView() . imageView.setImageBitmap(result) el código fuente y descubrí que originalmente son llamados por imageView.setImageBitmap(result) en el método onLoadComplete del cargador, y en ImageView :

/** * Sets a drawable as the content of this ImageView. * * @param drawable The drawable to set */ public void setImageDrawable(Drawable drawable) { ... int oldWidth = mDrawableWidth; int oldHeight = mDrawableHeight; updateDrawable(drawable); if (oldWidth != mDrawableWidth || oldHeight != mDrawableHeight) { requestLayout(); } invalidate(); } }

aquí, requestLayout() es el método de View y siempre se ejecuta en [Modo directo] o [Modo de cargador], en View.class:

public void requestLayout() { mPrivateFlags |= FORCE_LAYOUT; mPrivateFlags |= INVALIDATED; if (mLayoutParams != null) { mLayoutParams.onResolveLayoutDirection(getResolvedLayoutDirection()); } if (mParent != null && !mParent.isLayoutRequested()) { mParent.requestLayout(); } }

sin embargo, la diferencia es: en [Modo directo], mParent.requestLayout() se invoca una vez, pero en [Modo cargador], cada vez que llamo a imageView.setImageBitmap(result); , el mParent.requestLayout() también se invocará, significa mParent.isLayoutRequested() devuelve false , y mParent.requestLayout(); hará que GridView mida el diseño de su hijo al llamar a obtainView() al primer hijo y luego a getView(0, X, X) :

@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { ... mItemCount = mAdapter == null ? 0 : mAdapter.getCount(); final int count = mItemCount; if (count > 0) { final View child = obtainView(0, mIsScrap); ...

Entonces, mi pregunta es: ¿ mParent.isLayoutRequested() qué mParent.isLayoutRequested() devuelve false si estoy usando [modo cargador]? o es solo un caso normal?


Este es un comportamiento normal, Android puede llamar a getView para la misma posición varias veces. El desarrollador puede obtener / configurar la miniatura en getView solo cuando sea necesario (es decir, si no se configuró la miniatura o si la ruta de la miniatura tiene cambios). En otros casos, simplemente devuelva convertView, que obtenemos como parámetro en getView.


Yo tuve el mismo problema. Grid siempre mide su primer hijo, incluso si estoy en la posición 30.
Simplemente omito todo el código de getView agregando esta comprobación en la parte superior de getView:

@Override public View getView(final int position, View convertView, ViewGroup parent) { // Patch for multiple getView for position 0 if(convertView!=null && position==0 && viewGrid.getFirstVisiblePosition()>1) return convertView;

Esto no evita que se llame a getView, pero al menos los textos, las imágenes y los cambios de diseño no se ejecutan.


intente ajustar su diseño xml en cualquier lugar que haga referencia a la altura, ya que el androide hará una medida para dibujar cada vez y volverá a dibujar la celda. Intente usar en listview match_parent y en la celda en la fila una altura exacta. perdón mi Inglés es malo.


isLayoutRequested está justo allí para indicarle si ya hay un diseño pendiente para esta View . Es decir, después de llamar a isLayoutRequested , isLayoutRequested devolverá verdadero hasta que se complete el siguiente paso de diseño. La única razón para esta comprobación en requestLayout es evitar llamar repetidamente a requestLayout en el padre si está a punto de hacer el diseño de todos modos. isLayoutRequested es una isLayoutRequested falsa aquí: no es la causa de que se llame repetidamente a onMeasure .

El problema raíz es que ImageView solicita un nuevo diseño cada vez que cambias su dibujo. Esto es necesario por dos razones:

  1. El tamaño de ImageView puede depender del tamaño del adjustViewBounds , si se configura adjustViewBounds . Esto podría, a su vez, afectar el tamaño de otras vistas, según el diseño: ImageView no tiene suficiente información para saber.
  2. ImageView.onMeasure es responsable de determinar cuánto debe ajustarse el tamaño del dibujo para que se ajuste a los límites de ImageView , de acuerdo con el modo de escala. Si el nuevo dibujo no tiene el mismo tamaño que el dibujo viejo, debe volver a medir el ImageView para volver a calcular la escala requerida.

Solo puede solucionar el problema de tener demasiados cargadores manteniendo un caché local de Bitmap de Bitmap devueltos por los cargadores. La memoria caché puede tener todos los Bitmap si sabe que no hay tantos o solo los n utilizados más recientemente. En su getView , primero verifique si el Bitmap de Bitmap para ese elemento existe en el caché, y si es así, devuelva un ImageView ya establecido en ese Bitmap . Solo si no está en el caché necesitas usar un cargador.

Tenga cuidado: si los datos subyacentes pueden cambiar, ahora debe asegurarse de invalidar el caché al mismo tiempo que llama a invalidate en GridView o notificar a través de ContentResolver . He utilizado algún código de fabricación casera para lograr esto en mi aplicación, y funciona bien para mí, pero la buena gente de Square tiene una biblioteca de código abierto llamada Picasso para hacer todo el trabajo por ti si lo prefieres.