I'm working on dynamically setting a text of TextView in a fragment called 'ChallengeFragment' by creating a method that sets the text. Then, I call the method in FragmentActivity class to update the TextView. However, I am getting error that TextView object is null when the method is called. I am not sure why TextView is null.
Here's the logcat message:
16:36:02.437 4072-4072/eie.android.crunch E/AndroidRuntime﹕ FATAL EXCEPTION: main
Process: eie.android.crunch, PID: 4072
java.lang.RuntimeException: Unable to start activity ComponentInfo{eie.android.crunch/eie.android.crunch.ChallengePage}: 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:2325)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2390)
at android.app.ActivityThread.access$800(ActivityThread.java:151)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1303)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5257)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at
com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.TextView.setText(java.lang.CharSequence)' on a null object reference
at eie.android.crunch.ChallengeFragment.setNameText(ChallengeFragment.java:76)
at eie.android.crunch.ChallengePage.onCreate(ChallengePage.java:50)
at android.app.Activity.performCreate(Activity.java:5990)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1106)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2278)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2390)
at android.app.ActivityThread.access$800(ActivityThread.java:151)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1303)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5257)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)
Here is the Fragment class (ChallengeFragment.java):
public class ChallengeFragment extends Fragment {
private Activity mActivity;
private TextView nameText;
private Handler handler =new Handler();
public ChallengeFragment() {
}
public void onAttach(Activity activity) {
super.onAttach(activity);
mActivity = activity;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
LayoutInflater lf = getActivity().getLayoutInflater();
View v = lf.inflate(R.layout.fragment_challenge, null);
nameText = (TextView) v.findViewById(R.id.user_name_text_view);
....
return v;
}
public void setNameText(String s) {
nameText.setText(s);
}
public TextView getNameText() {
return nameText;
}
}
And this is the code for FragmentActivity that updates the text of TextView (ChallengePage.java):
public class ChallengePage extends FragmentActivity {
private FriendChallengeFragment initialFriendHabit;
private ChallengeFragment friendHabit;
private ChallengeFragment myHabit;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_challenge);
FragmentManager fm = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fm.beginTransaction();
myHabit = new ChallengeFragment();
initialFriendHabit = new FriendChallengeFragment();
myHabit.onAttach(ChallengePage.this);
initialFriendHabit.onAttach(ChallengePage.this);
fragmentTransaction
.replace(R.id.my_habit, myHabit ,"fragment_top")
.replace(R.id.friend_habit, initialFriendHabit, "fragment_bottom")
.commit();
Intent intent = getIntent();
String challengedUsername = intent.getStringExtra("username");
if(challengedUsername != null) {
friendHabit = new ChallengeFragment();
friendHabit.onAttach(ChallengePage.this);
fragmentTransaction.replace(R.id.friend_habit, friendHabit, "fragment_bottom");
friendHabit.setNameText(challengedUsername);
}
}
}
And this is the layout file that contains the fragment (fragment_challenge.xml):
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/white"
android:id="@+id/user_name_text_view"
android:layout_gravity="center_horizontal"
android:text="User Name"
android:textSize="30dp"
android:layout_marginTop="30dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/white"
android:id="@+id/habit_name_text"
android:layout_gravity="center_horizontal"
android:text="Habit Name"
android:textSize="40dp"
android:layout_marginTop="20dp"/>
<ProgressBar
android:layout_height="wrap_content"
android:layout_width="312dp"
style="@android:style/Widget.ProgressBar.Horizontal"
android:id="@+id/progressBar"
android:layout_marginTop="50dp"
android:layout_gravity="center_horizontal"/>
</LinearLayout>
I've looked at other stackoverflow questions relating to this but could not find answers.
The problem is your fragment's
setNameText()
method is called beforeonCreateView()
has run, so your TextView has not been initialized yet. You have to wait until later to set the name text.If you always have the name text when you are creating and adding the fragment, then it's better to pass that as an argument to the fragment and have it set the text of the TextView at the appropriate time. Something like this:
A few things to note:
newInstance
pattern is typically regarded as the best practice.onActivityCreated
because at that time you know the Activity is created and that the fragment's view hierarchy has been created.Also, you should not be calling
onAttach()
yourself, that's a lifecycle method that the OS calls on your fragment.