Добавьте в макет Android программно — затем получите доступ к тому, что было создано другим методом

#android #layout

#Android #макет

Вопрос:

Я создаю макет программно и мне нужно добавить TextView. Единственная проблема в том, что мне нужно сделать TextView глобальной переменной, чтобы к ней можно было обращаться с помощью разных методов (нужно вызвать метод setText () в другом месте).

 ScrollView scroll = new ScrollView(this);
LinearLayout linear = new LinearLayout(this);
linear.setOrientation(LinearLayout.VERTICAL);
scroll.addView(linear);

TextView time = new TextView(this);
time.setText("Some text");
linear.addView(time);

new CountDownTimer(30000, 1000) {
public void onTick(long millisUntilFinished) {
    time.setText("seconds remaining: "   millisUntilFinished / 1000);
} // 'time' not accessible

public void onFinish() {
 time.setText("done!");
}
}.start(); */

this.setContentView(scroll);
  

Итак, моя проблема в том, что я создаю текстовое представление ‘time’, но метод CountDownTimer не может получить к нему доступ. Я пытаюсь использовать TextView time = new TextView(this); в верхней части моего кода с конструкторами, чтобы он был глобальным, но это вызывает исключение — «невозможно создать activity ComponentInfo» и «исключение нулевой точки». Исключение не указывает, какая строка конкретно вызывает проблему, но это TextView timeLeft = new TextView(this); точно!

Комментарии:

1. Почему вы не используете файл XML layout для определения вашего представления? Просто любопытно.

2. Кроме того, где в вашем коде вы вызываете setContentView?

3. Это только часть кода (та часть, с которой у меня возникли проблемы). Причина, по которой я создаю макет программно, поскольку ранее к нему добавлено неопределенное количество кнопок. setContentView находится (как указано выше) в нижней части кода после каждой кнопки, а time TextView добавляется к макету.

4. Ах, извините. Я сосредоточился на верхней части кода и не увидел setContentView (). Ого!

Ответ №1:

Я бы создал переменную-член в вашем Activity ( mTime ). Тогда CountDownTimer сможет получить доступ к переменной-члену в любое время.

В качестве альтернативы вы можете объявить time final:

 final TextView time = new TextView(this);
  

Комментарии:

1. Теперь это работает, объявив time как final , это нормально для этого? time изменяется каждый раз, когда таймер останавливается, поскольку это таймер обратного отсчета. Я немного смущен тем, что делают конечные переменные, поскольку, похоже, это довольно удачно модифицирует его. Я полагаю, лучше залезть в Википедию и прочитать!

Ответ №2:

Вы могли бы назначить id (скажем: myTextViewId ) своему TextView перед добавлением его в представление, а позже вы можете просто ссылаться на это TextView с помощью findViewById(myTextViewId); .

Та же ситуация, если вы расширяете свой TextView, используя XML-файл, и назначаете идентификатор внутри него. Затем вы можете обратиться к этому TextView с помощью findViewById(R.id.myTextView); .

Или, наконец, поскольку вы не можете создать этот TextView одновременно final (он не будет инициализирован сразу или в конструкторе) и class-level (private, protected и т.д.), Я бы посоветовал сделать его частной переменной внутри вашего класса.

Чтобы получить к нему доступ, ваш метод должен выполняться в потоке пользовательского интерфейса, но у таймера есть свой собственный поток, поэтому вы должны использовать Handler , а из вашего TimreTask метода run просто отправьте ему пустое сообщение.
В вашем Handler handleMessage(Message msg) методе вы можете безопасно получить доступ к своему TextView , либо он является членом вашего класса, либо просто зная его id .