在Fragment中调用setText方法时出现NullPointerException问题求助
主Activity操作Fragment内TextView时出现NullPointerException
尝试从主Activity为Fragment内的TextView设置文本时触发NullPointerException,已在Fragment的onCreateView()方法中初始化TextView,但问题依旧。
Fragment布局代码 (fragment_card_back.xml)
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:text="@string/back_card" android:gravity="center" android:layout_width="217dp" android:layout_height="290dp" android:id="@+id/cardBack" app:layout_constraintBottom_toBottomOf="parent" android:layout_marginBottom="221dp" app:layout_constraintStart_toStartOf="parent" android:layout_marginStart="97dp" app:layout_constraintTop_toTopOf="parent" android:layout_marginTop="221dp" android:layout_marginEnd="97dp" app:layout_constraintEnd_toEndOf="parent" android:background="@drawable/bg_rounded" android:textSize="28sp" android:textColor="@color/black" android:fontFamily="@font/spy_font"/> </androidx.constraintlayout.widget.ConstraintLayout>
Activity布局代码 (activity_players_cards.xml)
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".PlayersCards" android:background="@color/white"> <FrameLayout android:layout_width="317dp" android:layout_height="465dp" app:layout_constraintTop_toTopOf="parent" android:layout_marginTop="1dp" app:layout_constraintStart_toStartOf="parent" android:layout_marginStart="1dp" app:layout_constraintBottom_toBottomOf="parent" android:layout_marginBottom="1dp" android:layout_marginEnd="1dp" app:layout_constraintEnd_toEndOf="parent" android:id="@+id/container"> </FrameLayout> </androidx.constraintlayout.widget.ConstraintLayout>
Activity代码 (PlayersCards.java)
public class PlayersCards extends AppCompatActivity { private boolean showingBack; public static List<Role> roles = new ArrayList<>(); FrameLayout card; CardBackFragment cardBackFragment = new CardBackFragment(); CardFrontFragment cardFrontFragment = new CardFrontFragment(); TextView playerLabel; public static class CardFrontFragment extends Fragment { TextView roleLabel, wordLabel; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view; view = inflater.inflate(R.layout.fragment_card_front, container, false); roleLabel = (TextView) view.findViewById(R.id.roleTextView); wordLabel = (TextView) view.findViewById(R.id.wordTextView); return view; } public CardFrontFragment setRoleLabel(String text) { roleLabel.setText(text); return this; } public CardFrontFragment setWordLabel(String text) { wordLabel.setText(text); return this; } } public static class CardBackFragment extends Fragment { TextView playerLabel; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view; view = inflater.inflate(R.layout.fragment_card_back, container, false); playerLabel = (TextView) view.findViewById(R.id.cardBack); return view; } public CardBackFragment setPlayerLabel(String text) { playerLabel.setText(text); return this; } } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_players_cards); if (savedInstanceState == null) { getSupportFragmentManager() .beginTransaction() .add(R.id.container, cardBackFragment) .commit(); } for (int i = 0; i < MainActivity.finalCountOfSpies; i++) { roles.add(Role.SPY); } for (int i = 0; i < MainActivity.finalCountOfPlayers - MainActivity.finalCountOfSpies; i++) { roles.add(Role.PLAYER); } Collections.shuffle(roles); card = findViewById(R.id.container); playerLabel = card.findViewById(R.id.cardBack); playerLabel.setText("TEXTTEXTTEXT"); card.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { flipCard(); } }); } private void flipCard() { if (showingBack) { getSupportFragmentManager() .beginTransaction() .setCustomAnimations( R.anim.card_flip_right_in, R.anim.card_flip_right_out, R.anim.card_flip_left_in, R.anim.card_flip_left_out ) .replace(R.id.container, cardBackFragment.setPlayerLabel("BLABLABLA")) .addToBackStack(null) .commit(); showingBack = false; } else { getSupportFragmentManager() .beginTransaction() .setCustomAnimations( R.anim.card_flip_left_in, R.anim.card_flip_left_out, R.anim.card_flip_right_in, R.anim.card_flip_right_out ) .replace(R.id.container, cardFrontFragment.setRoleLabel("ROLELABEL").setWordLabel("WORDWORDWORD")) .addToBackStack(null) .commit(); showingBack = true; } } }
错误信息
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.dadry.spygame/com.name.spygame.PlayersCards}: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.TextView.setText(java.lang.CharSequence)' on a null object reference at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2778) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2856) at android.app.ActivityThread.-wrap11(Unknown Source:0) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1589) at android.os.Handler.dispatchMessage(Handler.java:106) at android.os.Looper.loop(Looper.java:164) at android.app.ActivityThread.main(ActivityThread.java:6494) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807) Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.TextView.setText(java.lang.CharSequence)' on a null object reference at com.dadry.spygame.PlayersCards.onCreate(PlayersCards.java:102) at android.app.Activity.performCreate(Activity.java:7009) at android.app.Activity.performCreate(Activity.java:7000) at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1214) at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2731)
问题原因
- Fragment视图异步初始化:Activity中调用
getSupportFragmentManager().commit()后,Fragment的视图不会立刻创建,此时通过card.findViewById(R.id.cardBack)无法获取到Fragment内的TextView,导致playerLabel为null,调用setText时触发空指针。 - Fragment setter方法未做空判断:调用
cardBackFragment.setPlayerLabel()时,如果Fragment的onCreateView还未执行,内部的playerLabel还未初始化,直接调用setText也会触发空指针。
修复方案
1. 移除Activity中直接获取Fragment控件的代码
删除ActivityonCreate方法中以下代码:
playerLabel = card.findViewById(R.id.cardBack); playerLabel.setText("TEXTTEXTTEXT");
2. 修改Fragment的setter方法,适配视图未创建的情况
修改CardBackFragment,增加文本变量缓存,在视图创建时自动赋值:
public static class CardBackFragment extends Fragment { TextView playerLabel; private String cachedPlayerText; // 缓存文本 @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_card_back, container, false); playerLabel = view.findViewById(R.id.cardBack); // 视图创建后,如果有缓存文本则设置 if (cachedPlayerText != null) { playerLabel.setText(cachedPlayerText); } return view; } public CardBackFragment setPlayerLabel(String text) { this.cachedPlayerText = text; // 如果视图已创建,直接设置 if (playerLabel != null) { playerLabel.setText(text); } return this; } }
对CardFrontFragment做同样修改,避免flip时的空指针:
public static class CardFrontFragment extends Fragment { TextView roleLabel, wordLabel; private String cachedRoleText; private String cachedWordText; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_card_front, container, false); roleLabel = view.findViewById(R.id.roleTextView); wordLabel = view.findViewById(R.id.wordTextView); if (cachedRoleText != null) { roleLabel.setText(cachedRoleText); } if (cachedWordText != null) { wordLabel.setText(cachedWordText); } return view; } public CardFrontFragment setRoleLabel(String text) { this.cachedRoleText = text; if (roleLabel != null) { roleLabel.setText(text); } return this; } public CardFrontFragment setWordLabel(String text) { this.cachedWordText = text; if (wordLabel != null) { wordLabel.setText(text); } return this; } }
3. 正确设置初始文本
在Activity的onCreate中,先调用Fragment的setter方法再添加到容器:
if (savedInstanceState == null) { cardBackFragment.setPlayerLabel("TEXTTEXTTEXT"); getSupportFragmentManager() .beginTransaction() .add(R.id.container, cardBackFragment) .commit(); }
这样修改后,无论Fragment视图是否已创建,文本都会被正确设置,不会触发空指针异常。
内容的提问来源于stack exchange,提问作者drizh2
相关产品推荐
相关产品推荐

