Как получить доступ к представлениям, программно добавленным в пользовательское представление?

Я создал собственный класс, который расширяется от класса MaterialCardView, к которому я программно добавляю TextView следующим образом:

public class CustomQuestionView  extends MaterialCardView {

    private LinearLayout linearLayout;
    public TextView timeTextView;
    

  public CustomQuestionView(Context context, AttributeSet attributeSet) {
        super(context, attributeSet);

        this.linearLayout = new LinearLayout(context);
        LinearLayout.LayoutParams horizontalContentXLayoutParams = new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
        horizontalContentXLayoutParams.gravity = Gravity.CENTER;
        this.linearLayout.setLayoutParams(horizontalContentXLayoutParams);
        this.linearLayout.setOrientation(LinearLayout.VERTICAL);

        this.addView(linearLayout);

        this.timeTextView = new TextView(context);
        this.timeTextView.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
        this.timeTextView.setTextColor(Color.parseColor("#fcfc03"));
        this.timeTextView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 40);
        this.timeTextView.setText("What is your name?");
        this.linearLayout.addView(timeTextView);


   linearLayout.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(context, "This is a test", Toast.LENGTH_SHORT).show();
            }
        });

    }


    public CustomQuestionView (Context context){
        super(context);
    }


    public void setQuestion(String question){
        this.timeTextView.setText(question);
    }


}

Я создаю экземпляр CustomQuestionView в методе onViewCreated() моего фрагмента следующим образом:

   @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        customQuestionView = new CustomQuestionView(requireContext());
      //  customQuestionView.setQuestion("Is this my custom question?");
        
    }

И мой XML-код для моего фрагмента, где находится пользовательское представление, выглядит так:

<?xml version = "1.0" encoding = "utf-8"?>
<FrameLayout xmlns:android = "http://schemas.android.com/apk/res/android"
    xmlns:tools = "http://schemas.android.com/tools"
    android:layout_width = "match_parent"
    android:layout_height = "match_parent"
    tools:context = ".customviews.CustomViewsFragment">
    

    <LinearLayout
        android:layout_width = "match_parent"
        android:layout_height = "match_parent"
        android:orientation = "vertical"
        android:layout_gravity = "center">

        <TextView
            android:layout_width = "wrap_content"
            android:layout_height = "wrap_content"
            android:layout_gravity = "center_horizontal"
            android:layout_marginTop = "20dp"
            android:text = "Welcome!"/>
        
        <com.pedroprojects.adc2.customviews.CustomQuestionView
            android:layout_width = "match_parent"
            android:layout_height = "60dp"
            android:layout_gravity = "center_horizontal"
            android:layout_marginTop = "20dp"/>
        
    </LinearLayout>
    
</FrameLayout>

Создается CustomQuestionView, и я получаю начальный текст в TextView, отображаемом на экране, если я не вызываю метод setQuestion(), но проблема в том, что когда я пытаюсь изменить текст, вызывая setQuestion() метод (когда я раскомментировал закомментированную строку в моем методе onViewCreated()), приложение вылетает и выдает следующую ошибку:

java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.TextView.setText(java.lang.CharSequence)' on a null object reference
        at com.pedroprojects.adc2.customviews.CustomQuestionView.setQuestion(CustomQuestionView.java:74)
        at com.pedroprojects.adc2.customviews.CustomViewsFragment.onViewCreated(CustomViewsFragment.java:51)

Почему мой TextView имеет значение null в момент вызова этого метода, если я присваиваю ему значение в конструкторе? Как мне получить доступ к этому TextView, чтобы я мог изменить его после создания CustomQuestionView?

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
0
595
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Проблема здесь в том, что вызывается не конструктор, в котором вы инициализируете TextView, а другой конструктор. Таким образом, timeTextView имеет значение null, и когда вы пытаетесь вызвать customQuestionView.setQuestion, это вызывает NullPointerException и сбой.

Спасибо! Я скопировал свой код из конструктора CustomQuestionView (Context context, AttributeSet attributeSet) в конструктор CustomQuestionView(Context context), и теперь приложение не падает, когда я вызываю метод CustomQuestionView.setQuestion(), но и текст не обновляется. Вы знаете, что может быть причиной проблемы?

Pedro Orellana 10.12.2020 00:32

Вызывается другой конструктор, вы правы, но он вызывается через xml. Когда вы программно вызываете customQuestionView = new CustomQuestionView(requireContext());, для переменных экземпляра класса устанавливаются значения по умолчанию. Таким образом, это означает, что timeTextView имеет значение null, поскольку TextView никогда не инициализируется программно. И когда вы звоните CustomQuestionView.setQuestion(), это вызывает NullPointerException

akhil nair 10.12.2020 00:33

Причина, по которой текст не обновляется, заключается в том, что программно добавленное представление не добавляется в макет. Вы создаете два CustomQuestionView один через xml и один программно. Если вы хотите обновить текст, вы добавляете id к элементу в xml и делаете findViewById как обычно. Затем вызовите setQuestion() в этом экземпляре CustomQuestionView. Это должно работать.

akhil nair 10.12.2020 00:45

Вы правы, конструктор с 2-мя параметрами вызывается через XML, и после еще нескольких тестов я понял, что конструктор CustomQuestionView(Context context) мне не нужен. Все, что я сделал, это добавил идентификатор к своему пользовательскому представлению в моем XML-файле, а затем инициализировал его в коде моего фрагмента, например: customQuestionView = view.findViewById(R.id.my_custom_view_id); вместо того, чтобы делать customQuestionView = new CustomQuestionView(requireContext());, и теперь он работает отлично. Спасибо!

Pedro Orellana 10.12.2020 00:45

@PedroOrellana Если бы было здорово принять ответ, если бы он показался вам полезным. Спасибо

akhil nair 10.12.2020 00:52

Прежде всего, вы должны выбрать способ создания своего пользовательского представления: в коде или в xml. Представления имеют разные конструкторы для разных методов создания. У вас есть реализация только в конструкторе для создания из xml, но когда вы создаете представление из кода, вы не инициализируете linearlayout и кнопку, поэтому вы также должны инициализировать его в своем конструкторе CustomQuestionView (Context context), поэтому у вас есть свой ноль. И когда вы создаете свое представление из кода, вы должны создать свое представление в методе onCreateView и добавить его в корневое представление вашего фрагмента. А затем измените вопрос в методе onViewCreated.

Другие вопросы по теме