Восстановление иерархии представлений из сохраненного состояния не восстанавливает добавленные представления

Я пытаюсь сохранить и восстановить иерархию представлений, состоящую из таблицы кнопок. Количество строк таблицы и кнопок, требуемых в таблице, неизвестно до времени выполнения и добавляется программно к раздутому XML-макету в моем методе Activity onCreate(Bundle). Мой вопрос: можно сохранить и восстановить финальную таблицу с помощью сохранения/восстановления реализации Android по умолчанию?

Ниже приведен пример моей текущей попытки. При первом запуске таблица строится так, как ожидалось. Когда действие уничтожается (путем поворота устройства), пересмотренный вид показывает только пустой TableLayout без детей.

Файл xml, указанный в setContentView(int), включает, помимо прочего, пустой TableLayout, к которому добавлены кнопки.

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    // Setup this activity view.
    setContentView(R.layout.game_board);

    TableLayout table = (TableLayout) findViewById(R.id.table);

    // If this is the first time building this view, programmatically
    // add table rows and buttons.
    if (savedInstanceState == null) {
        int gridSize = 5;
        // Create the table elements and add to the table.
        int uniqueId = 1;
        for (int i = 0; i < gridSize; i++) {
            // Create table rows.
            TableRow row = new TableRow(this);
            row.setId(uniqueId++);
            for (int j = 0; j < gridSize; j++) {
                // Create buttons.
                Button button = new Button(this);
                button.setId(uniqueId++);
                row.addView(button);
            }
            // Add row to the table.
            table.addView(row);
       }
    }
}

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

Ответ 1

После поиска исходного кода для Activity, View и ViewGroup я узнал, что программно добавленные представления должны быть программно добавлены и каждый раз присваивается одинаковый идентификатор onCreate(Bundle). Это верно независимо от того, создает ли это представление в первый раз или воссоздает представление после уничтожения активности. Сохраненное состояние экземпляра программно добавленных просмотров затем восстанавливается во время вызова Activity.onRestoreInstanceState(Bundle). Самый простой ответ на приведенный выше код - просто удалить проверку для savedInstanceState == null.

protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    // Setup this activity view. 
    setContentView(R.layout.game_board); 

    TableLayout table = (TableLayout) findViewById(R.id.table); 

    int gridSize = 5;
    // Create the table elements and add to the table. 
    int uniqueId = 1; 
    for (int i = 0; i < gridSize; i++) { 
        // Create table rows. 
        TableRow row = new TableRow(this); 
        row.setId(uniqueId++);
        for (int j = 0; j < gridSize; j++) {
            // Create buttons.
            Button button = new Button(this);
            button.setId(uniqueId++);
            row.addView(button);
        }
        // Add row to the table.
        table.addView(row);
   }
}

Ответ 3

Эта строка воссоздает пустой макет:

setContentView(R.layout.game_board);

Кроме того, вы назначаете равный id строкам и кнопкам. Вы должны были использовать один счетчик для строк и кнопок:

    int idCounter = 1;
    for (int i = 0; i < gridSize; i++) {
        TableRow row = new TableRow(this);
        row.setId(idCounter++);
        for (int j = 0; j < gridSize; j++) {
            Button button = new Button(this);
            button.setId(idCounter++);
            row.addView(button);
        }
        ...
    }