Макет не обновляется после изменения ориентации

У меня есть следующее определение действия:

<LinearLayout
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:id="@+id/inspectionMainLayout"
    xmlns:android="http://schemas.android.com/apk/res/android">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:singleLine="false"
        android:id="@+id/breadCrumb"
        android:visibility="gone">
    </LinearLayout>

    <ExpandableListView
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:id="@+id/expandableListView" />

</LinearLayout>

Теперь в моем коде я динамически добавляю кнопки в хлебные крошки LinearLayout:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    setContentView(R.layout.activity_inspection);
    LinearLayout mainLayout = (LinearLayout) findViewById(R.id.inspectionMainLayout);

    if (mainLayout != null) {
        ExpandableListView list = (ExpandableListView) findViewById(R.id.expandableListView);

        list.setOnChildClickListener(new ExpandableListView.OnChildClickListener() {
            @Override
            public boolean onChildClick(ExpandableListView expandableListView, View view, int i, int i2, long l) {
                LinearLayout breadCrumb = (LinearLayout) findViewById(R.id.breadCrumb);

                Button filterButton = new Button(InspectionActivity.this);
                filterButton.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View view) {
                        onFilterButtonClick((Button) view);
                    }
                });

                filterButton.setText(item.getFormattedFilter());

                breadCrumb.addView(filterButton);
            }
        }
    }       
    ...
}

Этот код работает хорошо, пока я не изменю ориентацию устройства и моя активность не будет воссоздана. Хотя весь код выполняется правильно, экран не обновляется. Как только я восстанавливаю предыдущую ориентацию, все элементы внезапно появляются. Любая идея, почему и как это исправить?

Спасибо

РЕДАКТИРОВАТЬ:

Я действительно думаю, что столкнулся с той же проблемой, что описана в этом сообщении: Android: findViewById дает мне неправильный указатель?

Любая идея о том, как решить эту проблему?

По запросу мой onRestoreInstanceState:

@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
    super.onRestoreInstanceState(savedInstanceState);

    baseCategories = savedInstanceState.getParcelable(BASE_CATEGORIES_STATE);
    currentFilter = savedInstanceState.getParcelable(FILTERS_STATE);
}

и в onSaveInstanceState:

@Override
protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);

    outState.putParcelable(BASE_CATEGORIES_STATE, baseCategories);
    outState.putParcelable(FILTERS_STATE, currentFilter);
}

теперь оба моих класса реализуют интерфейс Parcelable. Они сохраняются и восстанавливаются правильно.

Тем не менее, по какой-то причине вызов findViewById get указывает на неправильный объект (не тот, который воссоздан).


person MaiOM    schedule 12.06.2014    source источник
comment
Можете ли вы опубликовать снимок экрана, чтобы мы могли понять, какие изменения вы получаете, возможно, это как-то связано с android:layout_height="50dp", потому что при изменении ориентации изменяется и высота.   -  person Girish Nair    schedule 12.06.2014
comment
Я не могу опубликовать скриншот, так как он содержит конфиденциальные данные. Каждый раз, когда действие воссоздается, ему не удается обновить пользовательский интерфейс. Например, после того, как он воссоздает действие, оно отображается правильно, но если я установлю, например, добавить новую кнопку внутри хлебной крошки, она не будет отображаться на экране, и все же, если я проверю объект хлебной крошки, новая добавленная кнопка есть. Я пытался аннулировать представление хлебных крошек, но все равно ничего. Есть идеи?   -  person MaiOM    schedule 12.06.2014
comment
Итак, вы хотите обновить или не обновить?   -  person jyoonPro    schedule 12.06.2014
comment
Хотелось бы как-нибудь освежить. Так, чтобы он отражал взгляды, которые внутри.   -  person MaiOM    schedule 12.06.2014


Ответы (2)


Вы добавляете представления динамически (по событию клика пользователя).
По умолчанию Android не "запоминает" сохранение этих динамических представлений при повторном создании активности при изменении конфигурации. Вы должны управлять этим процессом самостоятельно.

Некоторые возможности:

  • Избегайте повторного создания активности при повороте экрана, объявив android:configChanges="keyboardHidden|orientation|screenSize" для своей активности в AndroidManifest.xml. Это крайне не рекомендуется.

  • «Запоминать», какие представления были динамически добавлены при повторном создании активности после ротации (например, с помощью дополнительных флагов, чтобы определить, что была добавлена ​​новая кнопка фильтра, и передать ее через пакет в onSaveInstanceState и проверьте onCreate, нужно ли вам повторно создать кнопку), или сохраните весь объект представления, как описано здесь

Еще одно примечание: возможно, вы захотите указать «вертикальную» ориентацию для макета breadCrumb, по умолчанию она горизонтальная.

person kiruwka    schedule 12.06.2014
comment
Привет, я сохраняю некоторые данные уже в методе onSaveInstanceState и восстанавливаю их в RestoreInstanceState. После восстановления данных в методе onResume я повторно привязываю свой объект хлебных крошек, добавляя кнопки, которые были там ранее. Как только это будет сделано, если я попытаюсь добавить новую кнопку в это представление, она просто не будет отображаться. - person MaiOM; 12.06.2014
comment
Что я обнаружил до сих пор, так это то, что каким-то образом сохраняется ссылка на предыдущий экземпляр. Что я имею в виду, так это то, что если я вызову LinearLayout BreadCrumb = (LinearLayout) findViewById(R.id.breadCrumb); впервые мой var указывает на X. Затем класс воссоздается из-за изменения ориентации. Мой новый вызов findViewById(R.id.breadCrumb) указывает на другой объект. Однако, как только добавление запускается, и я снова вызываю findViewById(R.id.breadCrumb), он извлекает предыдущий адрес экземпляра. Это правдоподобно? Я говорю что-то глупое? - person MaiOM; 12.06.2014
comment
можете ли вы опубликовать код из onSave/onRestoreInstanceState, пожалуйста? - person kiruwka; 12.06.2014
comment
Ну, вы сохраняете/восстанавливаете данные, но я не вижу, где вы воссоздаете объект Button. Когда ваша активность воссоздается, вся ее иерархия представлений уничтожается, а затем вы снова раздуваете ее из макета xml. Если вы хотите увидеть свою динамическую кнопку, вам нужно создать ее снова, например, на основе сохраненного флага, указывающего, что кнопка была там до поворота. - person kiruwka; 12.06.2014
comment
Я узнал причину. проверьте мой ответ. Кажется, что если ваш класс реализует Parcelable, он все равно неявно сохраняет также частные переменные, которые не указаны в переопределении writeToParcel. Это происходило для моих частных прослушивателей ArrayList‹FilterItemListListener›; после восстановления он содержал указатель на предыдущий экземпляр представления. По неизвестной мне причине этот экземпляр все еще был действителен и возвращал действительный объект. - person MaiOM; 12.06.2014

Я узнал, почему это происходит.

onSave/onRestoreInstanceState Я сохранял класс currentFilter, в котором есть несколько пользовательских слушателей.

В качестве метода onResume я делал следующее:

@Override
protected void onResume() {
    if (currentFilter == null) {
            currentFilter = new FilterItemList();

            currentFilter.addListener(new FilterItemListListener() {
                @Override
                public void filterChanged(FilterChangedEvent e) {
                    filterCategories(categoryRepository);
                }

                @Override
                public void filterAdded(FilterAddedEvent e) {
                    FilterItem addedItem = e.getAddedItem();
                    baseCategories.remove(new BaseCategory("", addedItem.getSectionName()));
                }

                @Override
                public void filterRemoved(FilterRemovedEvent e) {
                    FilterItem removedItem = e.getRemovedItem();
                    baseCategories.add(new BaseCategory("", removedItem.getSectionName()));
                }
            });
    }
}

Указатель на предыдущий экземпляр был сохранен. Вот почему мой интерфейс вел себя неправильно.

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

Есть ли какой-то шаблон в решении этих ситуаций?

Спасибо

person MaiOM    schedule 12.06.2014
comment
По-видимому, класс Android Bundle не придерживается протокола разделения, который вместо этого используется при маршаллинге IPC. stackoverflow .com/questions/4853952/ - person MaiOM; 19.06.2014