Reputation: 21
I have an activity with a fragment on it that has a TextView inside. In the CourseFragment.java I made a simple method that changes the text of the TextView. However, when I try to call the fragment's method from the Activity, it says that the TextView object is null. Here is some of my code:
CourseFragment.java
public class CourseFragment extends Fragment {
private Subject subject;
View rootView;
private TextView title;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
rootView = inflater.inflate(R.layout.fragment_course, container,
false);
title = (TextView) rootView.findViewById(R.id.course_title);
return rootView;
}
public void setTitle() {
title.setText("My Title");
}
}
this is the code in my activity that makes the new fragment and puts in the right location:
CourseFragment fragment = new CourseFragment();
FragmentManager fm = getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.replace(R.id.course1, fragment);
fragment.setTitle();
ft.addToBackStack(null);
ft.commit();
the error coming from the setTitle() method inside the fragment
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.TextView.setText(java.lang.CharSequence)' on a null object reference
this seems so straight forward yet I don't understand why I keep getting NPE. I looked at similar questions about this and tried all the accepted solutions but to no avail. any ideas?
thanks in advance
edit: here is some more code as per requested:
the beginning of fragment_course.xml
<LinearLayout 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:id="@+id/course_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.stagenda.stagenda.CourseFragment"
android:padding="16dp"
android:orientation="vertical"
android:background="@android:color/background_light">
<RelativeLayout
android:layout_width="match_parent"
tools:ignore="UselessParent"
android:background="@color/colorAccent"
android:padding="16dp"
android:layout_height="wrap_content"
android:id="@+id/course_container">
<TextView
android:text="Course Given Title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/course_given_title"
android:textColor="@android:color/background_light"
android:textSize="18sp" />
<TextView
android:text="Course Title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/course_title"
android:layout_below="@+id/course_given_title"
android:textColor="@android:color/background_light" />
<TextView
android:text="Course Code"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/course_code"
android:textColor="@android:color/background_light"
android:layout_toRightOf="@+id/course_title"
android:layout_below="@+id/course_given_title"
android:layout_alignParentEnd="false"
android:layout_marginStart="10dp" />
full error:
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.stagenda.stagenda, PID: 1654
java.lang.IllegalStateException: Could not execute method for android:onClick
at android.support.v7.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:293)
at android.view.View.performClick(View.java:5639)
at android.view.View$PerformClick.run(View.java:22387)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6088)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)
Caused by: java.lang.reflect.InvocationTargetException
at java.lang.reflect.Method.invoke(Native Method)
at android.support.v7.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:288)
at android.view.View.performClick(View.java:5639)
at android.view.View$PerformClick.run(View.java:22387)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6088)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)
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.stagenda.stagenda.CourseFragment.setTitle(CourseFragment.java:34)
at com.stagenda.stagenda.MainPage.confirmAddCourse(MainPage.java:435)
at java.lang.reflect.Method.invoke(Native Method)
at android.support.v7.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:288)
at android.view.View.performClick(View.java:5639)
at android.view.View$PerformClick.run(View.java:22387)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6088)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)
I/Process: Sending signal. PID: 1654 SIG: 9
Disconnected from the target VM, address: 'localhost:8612', transport: 'socket'
Upvotes: 1
Views: 2599
Reputation: 657
The onCreateView()
method is called after fragmentTransaction.commit()
.
Since, you are calling setTitle()
before fragmentTransaction.commit()
, the TextView instance title
is not instantiated and so is null.
Add the line fragment.setTitle()
after fragmentTransaction.commit()
.
Upvotes: 0
Reputation: 21
I figured it out myself. The problem was here:
CourseFragment fragment = new CourseFragment();
FragmentManager fm = getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.replace(R.id.course1, fragment);
fragment.setTitle();
ft.addToBackStack(null);
ft.commit();
The problem was that I was calling setTitle() on fragment which did not have its view created. when instead I did the following the problem was solved:
CourseFragment fragment = new CourseFragment();
FragmentManager fm = getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.replace(R.id.course1, fragment);
ft.addToBackStack(null);
ft.commit();
CourseFragment frag = fm.findFragmentById(R.id.course1);
frag.setTitle();
I eventually changed a lot of my code but I hope this helps someone. thanks for the answers everyone
Upvotes: 1
Reputation: 2045
solved this problem by using Framgnet Callbacks as described in here http://developer.android.com/training/basics/fragments/communicating.html I believe that this is the best was to pass fragment TextViews into my activity after they are created.
Upvotes: 0
Reputation: 2819
One thing you can do is pass your data as parameters:
CourseFragment fragment = new CourseFragment(Your title);
FragmentManager fm = getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.replace(R.id.course1, fragment);
ft.addToBackStack(null);
ft.commit();
You can also use Bundle to pass your data.
Upvotes: 0
Reputation: 112
Layout for tabs:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:background="#ffffff">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_scrollFlags="scroll|enterAlways"
app:layout_collapseMode="pin"
android:background="#000000"
app:titleTextColor="#ffffff"
app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:popupTheme="@style/PopupMenuStyle">
<TextView
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:id="@+id/textview"
android:textColor="@color/colorTrueWhite"/>
</android.support.v7.widget.Toolbar>
<!-- our tablayout to display tabs -->
<android.support.design.widget.TabLayout
android:id="@+id/tabLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/colorBlack"
android:minHeight="?attr/actionBarSize"
app:tabIndicatorColor="@color/colorTrueWhite"
app:tabIndicatorHeight="5dp"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"/>
<!-- View pager to swipe views -->
<android.support.v4.view.ViewPager
android:id="@+id/pager"
android:layout_width="match_parent"
android:layout_height="fill_parent"/>
</LinearLayout>
Activity using that layout:
public class Main2Activity extends AppCompatActivity implements TabLayout.OnTabSelectedListener {
private TabLayout tabLayout;
public static ViewPager viewPager;
public static Context ctx;
Pager adapter;
public static int expired, paid;
Boolean isConnection;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
Toolbar tb = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(tb);
TextView tv = (TextView) findViewById(R.id.textview);
//getSupportActionBar().setDisplayHomeAsUpEnabled(true);
ctx = getApplicationContext();
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
tabLayout = (TabLayout) findViewById(R.id.tabLayout);
viewPager = (ViewPager) findViewById(R.id.pager);
tabLayout.addTab(tabLayout.newTab().setText("title1"));
tabLayout.addTab(tabLayout.newTab().setText("title2"));
tabLayout.addTab(tabLayout.newTab().setText("title3"));
tabLayout.setTabGravity(TabLayout.GRAVITY_FILL);
tabLayout.setupWithViewPager(viewPager);
adapter = new Pager(getSupportFragmentManager(), tabLayout.getTabCount(), ctx);
viewPager.setAdapter(adapter);
if(some condition)
{
viewPager.setCurrentItem(2);
}
else
{
viewPager.setCurrentItem(1);
}
viewPager.setOffscreenPageLimit(2);
tabLayout.addOnTabSelectedListener(this);
ViewGroup vg = (ViewGroup) tabLayout.getChildAt(0);
int tabsCount = vg.getChildCount();
for (int j = 0; j < tabsCount; j++) {
ViewGroup vgTab = (ViewGroup) vg.getChildAt(j);
int tabChildsCount = vgTab.getChildCount();
for (int i = 0; i < tabChildsCount; i++) {
View tabViewChild = vgTab.getChildAt(i);
if (tabViewChild instanceof TextView) {
((TextView) tabViewChild).setTypeface(Typeface.DEFAULT, Typeface.BOLD);
}
}
}
}
@Override
public void onTabSelected(TabLayout.Tab tab) {
viewPager.setCurrentItem(tab.getPosition());
}
@Override
public void onTabReselected(TabLayout.Tab tab) {
}
@Override
public void onTabUnselected(TabLayout.Tab tab) {
}
}
Pager code:
public class Pager extends FragmentStatePagerAdapter
{
int tabcount;
Context ctx;
private String [] Titles = {"title1", "title2", "title3"};
public Pager(FragmentManager fm, int tabcount, Context ctx)
{
super(fm);
this.tabcount = tabcount;
this.ctx = ctx;
}
@Override
public int getCount() {
return tabcount;
}
@Override
public CharSequence getPageTitle(int position) {
return Titles[position];
}
@Override
public Fragment getItem(int position) {
switch (position) {
case 0:
Tab1 tab1 = new Tab1();
return tab1;
case 1:
Tab2 tab2 = new Tab2();
return tab2;
case 2:
Tab3 tab3 = new Tab3();
return tab3;
default:
return null;
}
}
}
Upvotes: 0
Reputation: 3248
Fragment transactions are not synchronous. When you add a transaction it can be executed when the main looper has a chance to run it (it gets queued for later).
This means that the fragment gets attached until after the current method ends. Check the order in which CourseFragment.setTitle()
and onCreateView()
are executed.
See docs for FragmentTransaction.commit(): commit
Consider using commitNow()
if it works for you.
Also, consider passing the title as an argument to the fragment so that it can be read inside onCreateView
using getArguments()
.
Upvotes: 0
Reputation: 1251
Go with this approch.
Bundle bundle = new Bundle();
bundle.putString("title", "whatever you want to pass");
CourseFragment fragment = new CourseFragment();
fragment.setArguments(bundle);
FragmentManager fm = getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.replace(R.id.course1, fragment);
ft.addToBackStack(null);
ft.commit();
public class CourseFragment extends Fragment {
private Subject subject;
View rootView;
private TextView title;
Bundle bundle;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
bundle = getArguments();
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
rootView = inflater.inflate(R.layout.fragment_course, container,
false);
title = (TextView) rootView.findViewById(R.id.course_title);
String text = bundle.getString("title");
title.setText(text);
return rootView;
}
}
Upvotes: 2