Я создал собственный класс, который расширяется от класса 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?
Проблема здесь в том, что вызывается не конструктор, в котором вы инициализируете TextView, а другой конструктор. Таким образом, timeTextView
имеет значение null, и когда вы пытаетесь вызвать customQuestionView.setQuestion
, это вызывает NullPointerException
и сбой.
Вызывается другой конструктор, вы правы, но он вызывается через xml. Когда вы программно вызываете customQuestionView = new CustomQuestionView(requireContext());
, для переменных экземпляра класса устанавливаются значения по умолчанию. Таким образом, это означает, что timeTextView
имеет значение null, поскольку TextView никогда не инициализируется программно. И когда вы звоните CustomQuestionView.setQuestion()
, это вызывает NullPointerException
Причина, по которой текст не обновляется, заключается в том, что программно добавленное представление не добавляется в макет. Вы создаете два CustomQuestionView
один через xml и один программно. Если вы хотите обновить текст, вы добавляете id
к элементу в xml и делаете findViewById
как обычно. Затем вызовите setQuestion()
в этом экземпляре CustomQuestionView
. Это должно работать.
Вы правы, конструктор с 2-мя параметрами вызывается через XML, и после еще нескольких тестов я понял, что конструктор CustomQuestionView(Context context)
мне не нужен. Все, что я сделал, это добавил идентификатор к своему пользовательскому представлению в моем XML-файле, а затем инициализировал его в коде моего фрагмента, например: customQuestionView = view.findViewById(R.id.my_custom_view_id);
вместо того, чтобы делать customQuestionView = new CustomQuestionView(requireContext());
, и теперь он работает отлично. Спасибо!
@PedroOrellana Если бы было здорово принять ответ, если бы он показался вам полезным. Спасибо
Прежде всего, вы должны выбрать способ создания своего пользовательского представления: в коде или в xml. Представления имеют разные конструкторы для разных методов создания. У вас есть реализация только в конструкторе для создания из xml, но когда вы создаете представление из кода, вы не инициализируете linearlayout и кнопку, поэтому вы также должны инициализировать его в своем конструкторе CustomQuestionView (Context context), поэтому у вас есть свой ноль. И когда вы создаете свое представление из кода, вы должны создать свое представление в методе onCreateView и добавить его в корневое представление вашего фрагмента. А затем измените вопрос в методе onViewCreated.
Спасибо! Я скопировал свой код из конструктора
CustomQuestionView (Context context, AttributeSet attributeSet)
в конструкторCustomQuestionView(Context context)
, и теперь приложение не падает, когда я вызываю методCustomQuestionView.setQuestion()
, но и текст не обновляется. Вы знаете, что может быть причиной проблемы?