Может ли onMeasure быть пропущено при добавлении View в ViewGroup? - PullRequest
10 голосов
/ 10 июня 2011

Ответил

У меня есть RelativeLayout, где я динамически добавляю представления, когда пользователь прокручивает по вертикали или по горизонтали. Я прокрутил свой собственный ViewRecycler, так как потенциально есть тысячи представлений, которые могли бы составить все, что можно прокручивать, но я показываю только 30 или около того в любое время. Подумайте о увеличенном виде календаря.

У меня возникают проблемы с производительностью, когда я добавляю представления, которые должны быть видны, onMeasure вызывается для RelativeLayout, каскадно переходящего к onMeasure, вызываемому для всех его дочерних представлений. У меня уже есть рассчитанный размер того, насколько большим будет RelativeLayout, и я установил его на свой LayoutParameters, так что измерение ViewGroup не требуется, равно как и повторное измерение видов, которые уже были добавлены, с их окончательным размером и новым добавленное представление не имеет отношения к этим представлениям.

Простым примером, демонстрирующим проблему, является добавление / удаление View для RelativeLayout и наблюдение за вызовом onMeasure, несмотря на тот факт, что это не влияет на размер RelativeLayout или положение других представлений.

main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout  xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/shell"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">
    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content">
</LinearLayout>

MyActivity.java

public class MyActivity extends Activity
{

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        ViewGroup shell = (ViewGroup) findViewById(R.id.shell);

        final RelativeLayout container = new RelativeLayout(this) {
            @Override
            protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
                super.onMeasure(widthMeasureSpec, heightMeasureSpec);
                Log.d("MyActvity", "onMeasure called on map");
            }
        };
        container.setBackgroundColor(Color.rgb(255, 0, 0));
        ViewGroup.LayoutParams containerParams = new ViewGroup.LayoutParams(300, 300);

        final TextView childView = new TextView(this);
        childView.setBackgroundColor(Color.rgb(0, 255, 0));
        childView.setText("Child View");

        Button viewToggle = (Button) findViewById(R.id.button);
        viewToggle.setText("Add/Remove Child View");

        viewToggle.setOnClickListener(new View.OnClickListener() {

            public void onClick(View view) {
                if (childView.getParent() == null) {
                    container.addView(childView, 400, 30);
                } else {
                   container.removeView(childView);
                }
            }
        });

        shell.addView(container, containerParams);
    }
}

При выполнении этого вы увидите 2 начальных (ожидаемых) вызова onMeasure, затем по одному для каждого добавления / удаления представления, нажав кнопку. Это, очевидно, работает нормально, но вы можете видеть, где постоянные вызовы onMeasure, когда у вас сложный макет вложенных представлений, могут стать проблематичными.

Есть ли рекомендуемый способ обхода этих вызовов onMeasure или хотя бы onMeasure, вызывающего measureChildren?

Ответы [ 3 ]

0 голосов
/ 17 сентября 2011

Я столкнулся с подобной проблемой, когда анимация происходит в размере группы просмотра, функция onMeasure () которой вызывается очень часто.Поскольку родительское представление содержит множество дочерних представлений, частые каскадные вызовы onMeasure () вызывали сбои производительности анимации.У меня есть другое грязное решение, но гораздо более простое, чем развертывание моего собственного layoutManager.

long mLastOnMeasurTimestamp;
...
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    ...
    long currentTimestamp = System.currentTimeMillis();
    if(currentTimestamp - mLastOnMeasureTimestamp < SKIP_PERIOD_IN_MILL){
        return;
    }
    mLastOnMeasureTimestamp = currentTimestamp;
    ...
0 голосов
/ 09 ноября 2011

Я столкнулся с подобной проблемой, и мое решение состояло в том, чтобы проверить, изменились ли размеры:

int parentWidth = MeasureSpec.getSize(widthMeasureSpec);
int parentHeight = MeasureSpec.getSize(heightMeasureSpec);
setMeasuredDimension(parentWidth, parentHeight);
if ( mClientWidth == parentWidth && mClientHeight == parentHeight ) {
    return;
}

mClientWidth = parentWidth;
mClientHeight = parentHeight;

Итак, если размеры родителя на самом деле не меняются, он не будет каскадно уменьшен доего дети.

0 голосов
/ 05 августа 2011

Вместо того, чтобы использовать свой собственный менеджер макетов (что я могу сделать в будущем), я изменил onMeasure на:

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    int count = getChildCount();
    for (int i = 0; count > i; i++) {
        View v = getChildAt(i);

        if (v.getVisibility() != GONE) {
            if (v.getMeasuredWidth() <= 0 || v.getMeasuredHeight() <= 0) {
                measureChild(v,
                    MeasureSpec.makeMeasureSpec(v.getLayoutParams().width,
                        MeasureSpec.AT_MOST),
                    MeasureSpec.makeMeasureSpec(v.getLayoutParams().height,
                        MeasureSpec.AT_MOST));
            }
        }
    }

    setMeasuredDimension(resolveSize(staticContainerWidth, widthMeasureSpec),
        resolveSize(staticContainerHeight, heightMeasureSpec));
}

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

int staticContainerHeight = 300;
int staticContainerWidth = 300;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...