Динамическая компоновка таблицы Android - добавление представлений вызывает исключение IllegalStateException (у ребенка уже есть родитель) - PullRequest
0 голосов
/ 11 ноября 2010

Создание макета в Java, так как необходимое количество TableLayouts не известно как время разработки.

Я получаю IllegalStateException, говорящий мне удалить View (из его текущего родителя) перед назначением егодругой родитель, когда я вызываю createPlayerTables()

Исключение выдается на первой строке в этом цикле, когда я пытаюсь добавить ImageView из списка ImageViews в первый TableRow:

for (int i = 0; i < 3; i++) {
    tableRowsLst.get(0).addView((ImageView) imageViewsLst.get(i));
    tableRowsLst.get(1).addView((ImageView) imageViewsLst.get(i+3));
}

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

// List<ImageView> imageViewsLst = new ...
// List<TableRow> tableRowsLst = new ...

/**
* Initialises the TableLayouts, one per player
*/ 
private TableLayout createPlayerTables(int playerNum) {
    ...

    for (int i = 0; i < 6; i++) {
        imageViewsLst.add(new ImageView(this));
        ...
    }

    for (int i = 0; i < 3; i++) {
        tableRowsLst.add(new TableRow(this));
        ...
    }

    for (int i = 0; i < 3; i++) {
        tableRowsLst.get(0).addView((ImageView) imageViewsLst.get(i));
        tableRowsLst.get(1).addView((ImageView) imageViewsLst.get(i+3));
    }

    ...
}

Ответы [ 3 ]

4 голосов
/ 11 ноября 2010

В этом цикле:

for (int i = 0; i < 3; i++){
   tableRowsLst.add(new TableRow(this));
   tableRowsLst.get(i).setLayoutParams(
       new TableLayout.LayoutParams(LayoutParams.FILL_PARENT, dipToPixels(55)));
   tableRowsLst.get(i).setOrientation(LinearLayout.HORIZONTAL);
}

вы просто продолжаете добавлять новые TableRows к tableRowsLst, но всегда используете только первые три элемента.

Очистите список передцикл:

tableRowsLst.clear();
2 голосов
/ 02 мая 2011

Хотя в данном примере это не так, другой распространенной причиной этой проблемы является неправильное использование onCreateDialog() и onPrepareDialog(). onCreateDialog() вызывается только один раз, и все, что здесь сделано, будет сохраняться. Если вы добавляете динамический контент в макет (Dialog), вы, вероятно, захотите использовать onPrepareDialog(), что произойдет после создания, но перед каждым отображением. Цитировать из документации Android :

Перед отображением диалогового окна Android также вызывает необязательный метод обратного вызова onPrepareDialog (int, Dialog). Определите этот метод, если вы хотите изменять какие-либо свойства диалога каждый раз, когда он открывается. Этот метод вызывается каждый раз, когда открывается диалоговое окно, тогда как onCreateDialog (int) вызывается только в самый первый раз, когда открывается диалоговое окно. Если вы не определите onPrepareDialog (), то диалоговое окно останется таким же, каким оно было в прошлый раз, когда оно было открыто. Этому методу также передается идентификатор диалога вместе с объектом Dialog, созданным в onCreateDialog ().

1 голос
/ 11 ноября 2010

Aha! Хорошо, после нескольких неудачных попыток вот проблема.

imageViewsList является переменной-членом. Вы добавляете 6 представлений каждый раз, когда вызываете createPlayerTables, ТОГДА ИСПОЛЬЗУЯ ПЕРВЫЕ 6 каждый раз. Первый проход (игрок 0), без проблем. Второй проход (игрок 1): бум.

Вариант 1) Не сохраняйте их. Данный код не нуждается в них, хотя это не охватывает все основы в любом случае. Вы можете выкопать их из строк таблицы и уложить в крайнем случае.

Вариант 2) Сместить ваш доступ к imageViewsList на playerNum * 6 (который будет == imageViewsList.size() при первом вызове createPlayerTables())

Дружеский совет: Вы могли бы найти проблему несколькими способами:

  • Log.d () с идентификатором объекта перед каждым вызовом TableRow.add () обнаружил бы тот же идентификатор объекта, который использовался во втором проходе, за которым сразу следует ваше исключение.
  • Пошаговое выполнение вашего кода в Handy Dandy Debugger. Да, это большой код, который нужно пройти, чтобы выяснить, что происходит в этом случае. Пара разных точек останова облегчила бы просмотр вызова вызова createPlayerTables () и позволила бы вам войти в cpt () только тогда, когда он собирался выбросить.

Спрашивая себя «что я мог сделать, чтобы поймать это» каждый раз, когда вы обнаружили ошибку, НЕМЕДЛЕННО улучшите ваши навыки отладки.

...