0

I have been stuck on this for awhile, I am loading a fragment from within an activity (replacing another). It loads fine and I can see it and return to the previous fragment, but when I call a method to load data into it I get a null pointer exception. My first code was this...

public class MainActivity extends Activity implements MainListFragment.MainListListener, StoryFragment.StoryListener {

MainListFragment mainListFragment;
StoryFragment storyFragment;

. . .

public void onMainListClick(DBRecordType recordType, int recordID){

    switch(recordType){
        case story:{
            DBHandler dbHandler = new DBHandler(this, null, null, 1);
            Story story = dbHandler.getStory(recordID);
            Toast.makeText(getApplicationContext(), story.toString(), Toast.LENGTH_SHORT ).show();

            storyFragment = new StoryFragment();
            FragmentTransaction transaction = getFragmentManager().beginTransaction();
            transaction.replace(R.id.container, storyFragment);
            transaction.addToBackStack(null);
            transaction.commit();
            storyFragment.loadStory(story);
            break;
        }

I am getting this error:

java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.EditText.setText(java.lang.CharSequence)' on a null object reference
        at com.maniblett.listtest.StoryFragment.loadStory(StoryFragment.java:60)
        at com.maniblett.listtest.MainActivity.onMainListClick(MainActivity.java:104)

The method in the fragment is setting text in an edittext, here's the fragment method I am calling mName and mSummary are references to edit text widgets :

public void loadStory(Story story){
    mName.setText(story.get_name());
    mSummary.setText(story.get_summary());
}

Is it legal to refer to a fragment like this (calling a method on the same reference I used to add the fragment via the fragment manager)? It seems like I already have a reference to the fragment, so using find fragment by ID would be redundant but when I double checked everything I read seemed to indicate I needed to find the fragment using findFragmentByID or Tag first so changed my code to this...

storyFragment = new StoryFragment();
            FragmentTransaction transaction = getFragmentManager().beginTransaction();
            transaction.replace(R.id.container, storyFragment, "loadedFragment");
            transaction.addToBackStack(null);
            transaction.commit();
            StoryFragment loadedFragment = (StoryFragment)getFragmentManager().findFragmentByTag("loadedFragment");
            loadedFragment.loadStory(story);
            break;

But I get a similar error, which is:

java.lang.NullPointerException: Attempt to invoke virtual method 'void com.maniblett.listtest.StoryFragment.loadStory(com.maniblett.listtest.datamodel.Story)' on a null object reference
        at com.maniblett.listtest.MainActivity.onMainListClick(MainActivity.java:107)
        at com.maniblett.listtest.MainListFragment.onListItemClick(MainListFragment.java:156)
        at android.app.ListFragment$2.onItemClick(ListFragment.java:160)
        at android.widget.AdapterView.performItemClick(AdapterView.java:300)

I have verified the object I am sending is not null after creating it (the 'story' in the case statement is an enum). Again, the frgament loads and runs fine if I comment out the method call, it is just when I call the emthod on it it fails. so, I guess I don't have the actual fragment that is loaded? Can someone tell me what I'm doing wrong? (I did search many other similar topics but couldn't find anything which helped, I'm pretty new to android). Thanks to any who take the time to help!

StoryFragment class:

public class StoryFragment extends Fragment 
{
StoryListener activityCallback;
private EditText mName;
private EditText mSummary;

public interface StoryListener {
    public void onAddButtonClick(String text);
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

    final View rootView = inflater.inflate(R.layout.fragment_story, container, false);

    Button button = (Button)rootView.findViewById(R.id.button);
    mName = (EditText)rootView.findViewById(R.id.name);
    mSummary = (EditText)rootView.findViewById(R.id.summary);


    button.setOnClickListener(new Button.OnClickListener() {
        public void onClick(View v) {
            DBHandler dbHandler = new DBHandler(getActivity().getBaseContext(), null, null, 1);

            Story story = new Story(mName.getText().toString(),mSummary.getText().toString());
            dbHandler.addStory(story);
            activityCallback.onAddButtonClick("Story"); //use same callback for all record types passing back record type created?
        }
    } );

    return rootView;
}

@Override
public void onAttach(Activity activity) {
    super.onAttach(activity);
    try { activityCallback = (StoryListener) activity;
    }
    catch (ClassCastException e) {
        throw new ClassCastException(activity.toString()+ " must implement StoryListener");
    }
}

public void loadStory(Story story){
    mName.setText(story.get_name());
    mSummary.setText(story.get_summary());
}


}

2 Answers 2

3

Well, you should understand how android works in the first place. The onCreateView method gets called only when the fragment is going to come visible. So when you call loadstory immediately after the FragmentTransaction method its obvious you'll get an NullPointer Exception

My solution: Declare two variables in the StoryFragment as name and summary

Change the loadStory method is like this

public void loadStory(Story story){
    this.name = story.get_name();
    this.summary = story.get_summary();
}

Finally in the OnCreateView method of StoryFragment after change here appropriately

mName = (EditText)rootView.findViewById(R.id.name);
mSummary = (EditText)rootView.findViewById(R.id.summary);

//if your fragment is also gonna be called by some other manner you should check for null in this.name and this.summary before setting it to the `TextView`
mName.setText(this.name);
mSummary.setText(this.summary);
0

Thank you. That worked perfectly. Actually, what I did was create a private Story type and then in StoryFragment.loadStory I assigned it.

public void loadStory(Story story){
    mStory = story;
}

I also was able to then see that it works fine to not have to search for the fragment using findFragmentByID, this part worked:

storyFragment = new StoryFragment();
           FragmentTransaction transaction = getFragmentManager().beginTransaction();
            transaction.replace(R.id.container, storyFragment);
            transaction.addToBackStack(null);
            transaction.commit();
            storyFragment.loadStory(story);

Thanks very much for pointing me in the right direction here

Not the answer you're looking for? Browse other questions tagged or ask your own question.