Search code examples
androidandroid-studioandroid-layoutandroid-fragmentsandroid-activity

Initializing fragments outside of OnCreate() in Android


I am extremely new to Android development. I basically have an activity with some buttons, for example "seeTreePicture" and "seeSeaPicture". When I press a button, I want to use a fragment I called "ContentViewer" to display a random tree/sea picture, and also have buttons under the picture to destroy the ContentViewer fragment instance and go back to the menu. The issue is, if I try to use a Fragment Transaction anywhere other than onCreate() of the activity, I get a null pointer exception when I try to access the view in the fragment.

My activity and things related to the fragment:

public class SeeActivity extends AppCompatActivity {

DisplayFragment displayFragment;
Button seeTreeButton;
Button seeSeaButton;

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

    seeTreeButton = findViewById(R.id.seeTreeButton);
    seeSeaButton = findViewById(R.id.seeSeaButton);
    displayFragment = new DisplayFragment();

    seeTreeButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {

            FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
            fragmentTransaction.add(R.id.fragmentContainer, displayFragment);
            fragmentTransaction.commit();
            fragmentTransaction.addToBackStack(null);

            displayFragment.changeImage(randomTree);
        }
    });

}

}

In my fragment, change image simply changes the image source of the ImageView:

public void changeImage(int treeResource)
{
    img = getView().findViewById(R.id.imageView);
    img.setImageResource(treeResource);
}

I get a null pointer exception for trying to access the view from getView() in the fragment, meaning that onCreateView wasn't invoked. Yet if I put the same transaction in the onCreate() method of the activity, it works. What am I doing wrong?


Solution

  • The issue with your code is that you are accessing getView() of your fragment before the fragment has gone through the initialization of the view. The reason why you don't have the crash when you execute the transaction in your activity's onCreate() method is that by the time you click on a button your fragment has already gone through onCreateView() and initialized its view. Check out fragment lifecycle guide and bear in mind that you should not access your fragment view before it was created or after it was destroyed. For more information about why your fragment view is not initialized instantly check out this guide. As for the solution, consider setting arguments for your fragment before adding it to your transaction like here:

    Bundle args = new Bundle();
    args.putInt(DisplayFragment.IMG_RESOURCE_ARG, randomTree);
    displayFragment.setArguments(args);
    

    Then in your onCreateView() or onViewCreated() methods of your fragment restore the arguments like here and set the image resource:

    @Override
    public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
        int resourceId = requireArguments().getInt(IMG_RESOURCE_ARG);
        img = view.findViewById(R.id.imageView);
        img.setImageResource(resourceId);
    }