Nano Hash - криптовалюты, майнинг, программирование

В адаптере gridview getView(position == 0) вызывался слишком много раз, чтобы измерить макет, когда setImageBitmap() в загрузчике

У меня есть GridView для отображения некоторых значков.

ДО ТОГО, как я прочитал это Эффективное отображение растровых изображений с сайта разработчиков Android, я декодировал растровое изображение из локального пути непосредственно в getView() адаптера, например:

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

этот способ в любом случае работает нормально, я назвал его [Прямой режим], журнал вывода для метода getView() должен быть:

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)
...

затем я пытаюсь изменить код на [Режим загрузки], упомянутый в статье Отображение растровых изображений Эффективно, как показано ниже:

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

in loadIcon() :

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

в слушателе загрузчика:

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

По сути, это то же самое, что и тренировочный код, на самом деле, этот способ тоже отлично работает. Однако я обнаружил кое-что другое, в этом режиме метод getView() в адаптере вызывался слишком много раз, однако эти повторные вызовы этого метода всегда с параметром «позиция» == 0, это означает, что что-то вызывает getView(0, X, X) повторно.

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)

Это нехорошо, потому что я использую загрузчик в getView(). Я проверил исходный код и обнаружил, что они изначально вызываются imageView.setImageBitmap(result) в методе onLoadComplete загрузчика и в 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();
    }
}

здесь requestLayout() — это метод View, который всегда выполняется в [Direct Mode] или [Loader Mode] в View.class :

public void requestLayout() {
    mPrivateFlags |= FORCE_LAYOUT;
    mPrivateFlags |= INVALIDATED;

    if (mLayoutParams != null) {
        mLayoutParams.onResolveLayoutDirection(getResolvedLayoutDirection());
    }

    if (mParent != null && !mParent.isLayoutRequested()) {
        mParent.requestLayout();
    }
}

однако разница в том, что в [Direct Mode] mParent.requestLayout() вызывается один раз, а в [Loader Mode] каждый раз, когда я вызываю imageView.setImageBitmap(result);, mParent.requestLayout() также будет вызываться, это означает mParent.isLayoutRequested() return false и mParent.requestLayout(); заставят GridView измерить макет своего дочернего элемента, вызвав obtainView() для первого дочернего элемента, а затем вызовут 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);
    ...

Итак, мой вопрос: почему mParent.isLayoutRequested() возвращает false, если я использую [режим загрузчика]? или это обычный случай?



Ответы:


1

isLayoutRequested просто сообщает вам, ожидает ли макет для этого View. То есть после вызова requestLayout isLayoutRequested будет возвращать значение true до тех пор, пока не завершится следующий проход компоновки. Единственная причина для этой проверки в requestLayout состоит в том, чтобы избежать повторного вызова requestLayout для родителя, если он все равно собирается выполнить компоновку. isLayoutRequested здесь отвлекающий маневр: это не причина многократного вызова onMeasure.

Основная проблема заключается в том, что ImageView запрашивает новый макет всякий раз, когда вы меняете его возможность рисования. Это необходимо по двум причинам:

  1. Размер ImageView может зависеть от размера drawable, если установлено adjustViewBounds. Это, в свою очередь, может повлиять на размеры других представлений, в зависимости от макета: ImageView сам по себе не имеет достаточно информации, чтобы знать.
  2. ImageView.onMeasure отвечает за определение того, насколько нужно изменить размер чертежа, чтобы он соответствовал границам ImageView, в соответствии с режимом масштабирования. Если новый рисуемый объект не имеет того же размера, что и старый, ImageView необходимо снова измерить, чтобы повторно вычислить требуемое масштабирование.

Вы можете решить проблему слишком большого количества загрузчиков, только сохранив локальный кеш Bitmaps, возвращаемый загрузчиками. В кеше могут быть все Bitmap, если вы знаете, что их не так много, или только n, которые использовались последними. В вашем getView сначала проверьте, существует ли Bitmap для этого элемента в кеше, и если да, верните ImageView, уже установленный на этот Bitmap. Только если его нет в кеше, нужно использовать загрузчик.

Будьте осторожны: если базовые данные могут измениться, теперь вам нужно убедиться, что кеш недействителен одновременно с вызовом invalidate на GridView или уведомлением через ContentResolver. Я использовал некоторый самодельный код, чтобы добиться этого в своем приложении, и он отлично работает для меня, но у хороших людей в Square есть библиотека с открытым исходным кодом под названием Picasso, чтобы сделать всю тяжелую работу за вас, если вы предпочитаете.

09.08.2013

2

Это нормальное поведение, Android может вызывать getView для одной и той же позиции несколько раз. Разработчик должен получить/установить миниатюру в getView только при необходимости (т.е. если миниатюра не была установлена ​​или путь к миниатюре изменился). В других случаях просто верните convertView, который мы получаем как параметр в getView.

02.01.2013

3

У меня такая же проблема. Сетка всегда измеряет своего первого потомка, даже если я нахожусь в позиции 30.
Я просто обхожу весь код getView, добавляя эту проверку в getView top:

@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;

Это не останавливает вызов getView, но, по крайней мере, тексты, изображения и изменения макета не выполняются.

11.11.2015
  • Если вы можете иметь более одного элемента в строке, измените 1 на максимальное количество элементов в строке. 09.03.2017

  • 4

    попробуйте настроить макет xml в любом месте, которое ссылается на высоту, потому что андроид будет каждый раз выполнять меру для рисования и снова перерисовывать ячейку. Попробуйте использовать в списке match_parent и в ячейке в строке точно по высоте. извините за мой плохой английский.

    25.05.2013
    Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

    Как написать эффективное резюме
    Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

    Понимание расстояния Вассерштейна: мощная метрика в машинном обучении
    В обширной области машинного обучения часто возникает необходимость сравнивать и измерять различия между распределениями вероятностей. Традиционные метрики расстояния, такие как евклидово..

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..