Пользовательский вид изображения теряет состояние на Marshmallow

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

// SaveStatePhotoView.java

@Override
protected void onRestoreInstanceState(Parcelable state) {
    if (!(state instanceof SavedState)) {
        super.onRestoreInstanceState(state);
        return;
    }

    final SavedState ss = (SavedState) state;
    super.onRestoreInstanceState(ss.getSuperState());

    getViewTreeObserver().addOnGlobalLayoutListener(
        new ViewTreeObserver.OnGlobalLayoutListener() {

        @Override
        public void onGlobalLayout() {
            restoreSavedState(ss);
            getViewTreeObserver().removeGlobalOnLayoutListener(this);
        }
    });
}

Представление работает должным образом на Android 7.1.1 и Android 9.
На Android 6.0.1 состояние потеряно: представление изображения сбрасывается в исходное состояние, когда устройство вращается.

Я подготовил простой проект, чтобы продемонстрировать проблему. Обратите внимание, что я использую PhotoView 1.3.1 намеренно, потому что на данный момент не может включать транзитивные androidx зависимости.


comment
Я нашел этот ответ, который хорошо объясняет, как справиться с потерей состояния экземпляра при повороте устройства: /a>, я думаю, вы могли бы попытаться восстановить изображение в onCreate, как показано в ответе выше, дайте мне знать, если это поможет!   -  person Giorgio Bertolotti    schedule 13.03.2019


Ответы (1)


Примечание Это не проблема с PhotoView версии 2.3.0.

PhotoView претерпевает два макета при повторном создании для API 23 и более ранних версий. Для API 24+ существует только один проход компоновки. Что происходит, когда есть два прохода, так это то, что шкала (матрица), которая восстанавливается в onRestoreInstanceState() из SaveStatePhotoView, сбрасывается. В вашем коде вы удаляете глобальный прослушиватель макета после первого прохода, поэтому, когда матрица сбрасывается на втором проходе макета, вы его не улавливаете. Для API 24+ есть только один проход и шкала восстанавливается, а не сбрасывается. Вот почему вы видите проблему для API 23, а не для 24.

Я думаю, что настоящее исправление находится в PhotoView. Ванильный ImageView также проходит два прохода макета, поэтому я не думаю, что дополнительный проход макета является чем-то, что вызывает PhotoView. Однако я думаю, что PhotoView неправильно обрабатывает матрицу масштабирования для определенных API.

Вы можете решить эту проблему, установив масштаб на втором проходе для API 24+, выполнив что-то вроде этого:

@Override
protected void onRestoreInstanceState(Parcelable state) {
    if (!(state instanceof SavedState)) {
        super.onRestoreInstanceState(state);
        return;
    }

    final SavedState ss = (SavedState) state;
    super.onRestoreInstanceState(ss.getSuperState());

    getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        private int invocationCount = 0;

        // Only one layout pass for M and up. Otherwise, we'll see two and the
        // scale set in the first pass is reset during the second pass, so the scale we
        // set doesn't stick until the 2nd pass.
        @Override
        public void onGlobalLayout() {
            setScale(Math.min(ss.scale, getMaximumScale()), getWidth() * ss.pivotX,
                    getHeight() * ss.pivotY, false);

            if (Build.VERSION.SDK_INT > Build.VERSION_CODES.M || ++invocationCount > 1) {
                getViewTreeObserver().removeOnGlobalLayoutListener(this);
            }
        }
    });
}

Предыдущее основано на предоставленном демонстрационном приложении с PhotoView версии 1.3.1.

person Cheticamp    schedule 14.03.2019
comment
Отличный анализ! Спасибо. - Где именно вы увидели, что PhotoView проходит два прохода макета на Marshmallow? - person JJD; 16.03.2019
comment
@JJD Просто переопределите onLayout() в своем пользовательском представлении, поверните устройство и посчитайте, сколько раз оно вызывалось. Для API 24+ это только один раз, а для более низких API вызывается дважды. Я сделал быстрый тест, и это то же самое для прямого ImageView. - person Cheticamp; 16.03.2019
comment
Еще раз, спасибо. Обходной путь кажется успешным. Мерси. - person JJD; 22.03.2019