9

This one is driving me nuts. Basically, I want to create a ViewPager and add a few Fragments to it. Then, all I want to do, it set a value in one of the Fragment's TextViews. I can add the Fragments fine, and they attach, but when I go to findViewById() for one of the TextViews in the first Fragment it throws a NullPointerException. I, for the life of me, can't figure out why.

Here's my code so far, let me know if more is needed please.

public class SheetActivity extends FragmentActivity {

    // /////////////////////////////////////////////////////////////////////////
    // Variable Declaration
    // /////////////////////////////////////////////////////////////////////////
    private ViewPager               viewPager;
    private PagerTitleStrip         titleStrip;
    private String                  type;
    private FragmentPagerAdapter    fragmentPager;  //UPDATE

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_sheet);

        viewPager = (ViewPager) findViewById(R.id.viewPager);
        titleStrip = (PagerTitleStrip) findViewById(R.id.viewPagerTitleStrip);

        // Determine which type of sheet to create
        Intent intent = getIntent();
        this.type = intent.getStringExtra("type");
        FragmentManager manager = getSupportFragmentManager();
        switch (type) {
            case "1":
                viewPager.setAdapter(new InstallAdapter(manager));
                break;
            case "2":
                viewPager.setAdapter(new InstallAdapter(manager));
                break;
        }
        fragmentPager = (FragmentPagerAdapter) viewPager.getAdapter();  //UPDATE
    }

    @Override
    public void onResume() {
        super.onResume();

        fragmentPager.getItem(0).setText("something"); //UPDATE
    }

    class MyAdapter extends FragmentPagerAdapter {

        private final String[]      TITLES      = { "Title1", "Title2" };
        private final int           PAGE_COUNT  = TITLES.length;
        private ArrayList<Fragment> FRAGMENTS   = null;

        public MyAdapter(FragmentManager fm) {
            super(fm);
            FRAGMENTS = new ArrayList<Fragment>();
            FRAGMENTS.add(new FragmentA());
            FRAGMENTS.add(new FragmentB());
        }

        @Override
        public Fragment getItem(int pos) {
            return FRAGMENTS.get(pos);
        }

        @Override
        public int getCount() {
            return PAGE_COUNT;
        }

        @Override
        public CharSequence getPageTitle(int pos) {
            return TITLES[pos];
        }
    }
}

All of Fragments I created only have the onCreateView() method overridden so I can display the proper XML layout. Other than that they are 'stock'. Why can't I interact with elements in any of the Fragments?

UPDATE:

So do something like this?

public class FragmentA extends Fragment {

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle inState) {
        return inflater.inflate(R.layout.fragment_a, container, false);
    }

    public void setText(String text) {
        TextView t = (TextView) getView().findViewById(R.id.someTextView);  //UPDATE
        t.setText(text);
    }
}

XML LAYOUT FOR FRAGMENT A

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical" >

    <TextView
        android:id="@+id/someTextView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:textSize="22sp" />

</LinearLayout>
mandelbug
  • 1,548
  • 5
  • 20
  • 32

4 Answers4

6

The TextView is located in the fragments layout, not in the ViewPagers or the PagerAdapter, that is causing the NPE. Now, you have 2 options.

  • The first is the easiest, you should simple move your code for changing the text into the corresponding fragment's class, FragmentA in this case.
  • Secondly, you could make the TextView into FragmentA static, so it can be accessed by other classes. So your code would look something like this:

     ....
     TextView myText;
    
     @Override
     public View onCreateView(....) {
    
         myLayout = ....;
    
         myText = myLayout.findViewById(yourID);
    
         ....
    }
    

And then you would change the text from somewhere else (if it's really necessary):

   FragmentA.myText.setText("new text");

Explaining method 2

Use the following in your Fragment.

public static void setText(String text) {
    TextView t = (TextView) getView().findViewById(R.id.someTextView);
    t.setText(text);
}

Then change the text like:

FragmentA.setText("Lulz");
Aashir
  • 2,621
  • 4
  • 21
  • 37
  • Earlier, I tried something like `getActivity().findViewById(R.id.someTextViewInFragmentA);` and instantiating that as a `TextView`. But when I tried to set the text on that, I received another NPE. – mandelbug Jul 03 '14 at 16:56
  • In onCreateView(..) you're supposed to use the variable you assign to layout you are inflating and get the ID's from that as I've shown above. Anyway, for the second method to work, the fragment must be started already or you'll receive another NPE. – Aashir Jul 03 '14 at 16:59
  • Updated my question above. Something like that? That gave me an NPE too. – mandelbug Jul 03 '14 at 17:13
  • Oh and I forgot to say, in fragments to get a reference to a view, you use getView() instead of getActivity(). Make the changes from getActivity() to getView() and your issue should be resolved. – Aashir Jul 03 '14 at 17:15
  • Where are you calling setText(..) ? – Aashir Jul 03 '14 at 17:25
  • Tried in the Fragment itself, but it doesn't get to it because the `getView().findViewById()` gives me an NPE. Also tried by grabbing it directly from the activity, but same sad story. – mandelbug Jul 03 '14 at 17:30
  • You're sure the TextView you're trying to find is in the layout of the fragment right? Also, the method is setText(...) not static, how and where are you calling it? – Aashir Jul 03 '14 at 17:33
  • Updated the code above. I used a `FragmentPagerAdapter` to get the fragment and set the text. – mandelbug Jul 03 '14 at 17:41
  • You do know that you're not changing the text right? By default it's set to "something" and then you're trying to set "something" as text again, which is not applied. Use my code for setText(..), I've updated my answer. – Aashir Jul 03 '14 at 17:44
  • Yeah I know, I just did it to get ANYTHING at all to be set to the `TextView`, just as proof it works. Once I can set the text, changing what the text is set to is easy. – mandelbug Jul 03 '14 at 17:49
  • http://stackoverflow.com/questions/39907625/why-is-accessing-textview-of-a-fragment-inside-activity-throwing-an-error I get an NPE – Si8 Oct 07 '16 at 10:38
4

Unless you are planning to change the value at runtime, you can pass the value into the fragment as a parameter. It is done my using a Bundle and passing it as args into a Fragment, which then retrieves it from it's args. More info here. If you implement this, your instantiation of new Fragments might look something like this:

public InstallAdapter(FragmentManager fm) {
            super(fm);
            FRAGMENTS = new ArrayList<Fragment>();
            FRAGMENTS.add(FragmentA.newInstance("<text to set to the TextView>"));
            FRAGMENTS.add(FragmentB.newInstance("<text to set to the TextView>"));
        }

If, however, you are planning to update the value at runtime (it will change as user is running the app), then you want to use an Interface to channell communication between your fragment and your activity. Info here. This is what it might look like:

//Declare your values for activity;
    ISetTextInFragment setText;
    ISetTextInFragment setText2;
...
//Add interface
public interface ISetTextInFragment{
    public abstract void showText(String testToShow);
}
...
//your new InstallAdapter
public InstallAdapter(FragmentManager fm) {
        super(fm);

        FRAGMENTS = new ArrayList<Fragment>();

        Fragment fragA = new FragmentA();
        setText= (ISetTextInFragment)fragA;
        FRAGMENTS.add(fragA);

        Fragment fragB = new FragmentB();
        setText2= (ISetTextInFragment)fragB;
        FRAGMENTS.add(fragB);
}

//then, you can do this from your activity:
...
setText.showText("text to show");
...

and it will update your text view in the fragment.

While it can be done "more easily", these methods are recomended because they reduce chances of bugs and make code a lot more readable and maintainable.

EDIT: this is what your Fragment should look like (modified your code):

public class FragmentA extends Fragment implements ISetTextInFragment {

    TextView myTextView;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle inState) {
        View v = inflater.inflate(R.layout.fragment_a, container, false);
        myTextView = (TextView)v.findViewbyId(R.id.someTextView)
        return v;
    }

    @Override
    public void showText(String text) {
        myTextView.setText(text);
    }
}

If after that you are still getting a null pointer exception, your TextView is NOT located where it needs to me, namely in the R.layout.fragment_a filem, and it needs to be located there. Unless you are calling the interface method BEFORE the fragment finished loading, of course.

Community
  • 1
  • 1
C0D3LIC1OU5
  • 8,600
  • 2
  • 37
  • 47
  • I will be doing the latter, of the two. I have used a `Communicator` interface to make `Fragment`s talk before, but they would let me `findViewById` for elements in the `Fragments` - this will not for some reason. – mandelbug Jul 03 '14 at 17:12
  • You want to instantiate your text view when you are creating it (in your onCreateView()), and then set it in the interface override method. – C0D3LIC1OU5 Jul 03 '14 at 17:19
  • If you call getView().findViewById() IN THE FRAGMENT, it will find your TextView. If you do it in YOUR ACVIVITY, it will not find it. – C0D3LIC1OU5 Jul 03 '14 at 17:21
  • Another NPE when calling `getView().findViewById()` IN THE FRAGMENT. – mandelbug Jul 03 '14 at 17:24
  • Your TextView is in the .xlm file you inflate in your fragments onCreateView, right? Can you post your code? – C0D3LIC1OU5 Jul 03 '14 at 17:30
  • Yes its the only thing in there, see above. – mandelbug Jul 03 '14 at 17:45
  • Aright, we are getting somewhere. I changed my `FragmentA` class as recommended above. I tried calling the `setText` method exactly as above (grabbing the fragment from the `FragmentPagerAdapter`), but that gave me an NPE. If I just put `myTextView.setText('Something');` right before the return statement in `onCreateView`, it worked. So we are halfway there. Am I grabbing the `FragmentA` instance correctly? – mandelbug Jul 03 '14 at 17:59
  • Sorry looked through your code - implement an interface as i suggested, i think this will resilve your issue. – C0D3LIC1OU5 Jul 03 '14 at 18:02
  • Added it and that too give me a NPE. I just don't understand. I try to grab `getActivity()` for a `Toast` in the `setText` method in `FragmentA` and that even throws a NPE. Its like the `Fragment` isn't retaining anything. – mandelbug Jul 03 '14 at 18:53
  • I think by the time you are grabbing it, your fragment is in the detached state- that would explain your NPE's. This is a different issue, but please look here for more info. http://stackoverflow.com/questions/11631408/android-fragment-getactivity-sometime-returns-null – C0D3LIC1OU5 Jul 07 '14 at 14:12
  • Ended up doing something similar to this. Thanks for the help! – mandelbug Jul 07 '14 at 14:33
  • Can you please assist with mine? http://stackoverflow.com/questions/39907625/why-is-accessing-textview-of-a-fragment-inside-activity-throwing-an-error – Si8 Oct 07 '16 at 10:27
1

This line:

TextView t = (TextView) findViewById(R.id.someTextViewInFragmentA);

is looking for the view in your ParentActivity. Of course it wont find it and that's when you get your NPE.

Try something like this:

  1. Add a "tag" to your fragments when you add them

  2. Use someFragment = getSupportFragmentManager().findFragmentByTag("your_fragment_tag")

  3. Get the view of the fragment fragmentView = someFragment.getView();

  4. And finally find your TextView and set the text

    TextView t = (TextView) fragmentView.findViewById(R.id.someTextViewInFragmentA); t.setText("some text");

Scopey
  • 6,269
  • 1
  • 22
  • 34
Carlos J
  • 2,965
  • 4
  • 17
  • 28
  • That is what I would normally do, but the Fragments are added by `MyAdapter`, so I don't get to tag them. – mandelbug Jul 03 '14 at 16:51
  • Can you post the code of `MyAdapter`? I think there's a way to add the tags in there – Carlos J Jul 03 '14 at 16:54
  • Also @Aashir has a fair point. Can you not update the `TextView` from your `Fragment` class? Isn't that easier? – Carlos J Jul 03 '14 at 16:57
  • Updated my question above. Something like that? That gave me an NPE too. – mandelbug Jul 03 '14 at 17:14
  • Close. Two things you are missing: 1. You are still trying to find the `TextView` in your ParentActivity, that's why you still have the NPE. Change this `TextView t = (TextView) getView().findViewById(R.id.someTextView);` 2. Change the method to be: `public static void setText(String text)` And then you can access it from your onResume Method in the MainActivity like this: FragmentA.setText("your text"); – Carlos J Jul 03 '14 at 17:28
  • Would I have to do that, or would something similar to my latest update work? – mandelbug Jul 03 '14 at 17:41
  • I did in a way. I don't want to make it static, because there will be different variations of the `ViewPager` shown based on what the result of the previous `Activity` is. Therefore, I used the `FragmentPagerAdapter` to grab the Fragment, and use the `setText` method. Still NPE though. – mandelbug Jul 03 '14 at 17:47
  • Can you please assist with mine? http://stackoverflow.com/questions/39907625/why-is-accessing-textview-of-a-fragment-inside-activity-throwing-an-error – Si8 Oct 07 '16 at 10:28
0

How about to change this line

TextView t = (TextView) getView().findViewById(R.id.someTextView);  //UPDATE

to

TextView t = (TextView) getActivity().findViewById(R.id.someTextView);  //UPDATE

then you can try to update "t" with .setText("some_string") inside "SheetActivity".

Shog9
  • 156,901
  • 35
  • 231
  • 235
Artis JIANG
  • 61
  • 1
  • 7