7

I have a SignupActivity which will go through several fragments as users go through a signup process. On the last fragment, I'm calling

getActivity().setResult(Activity.RESULT_OK) 

since SingupActivity intent was started for result. Some users are crashing at this point, because getActivity() is producing a NPE. I'm not able to figure out what is causing this. Screen rotation is disabled, so there is no reason that I know of for the fragment to detach from the Activity.

Any insight as to what may be causing this, and how I can resolve it?

public class SignupConfirmationFragment extends Fragment {
    public static final String TAG = SignupConfirmationFragment.class.getSimpleName();
    private User mNewUser;
    private myAppClient mmyAppClient;

    private Animation rotateAnimation;
    private ImageView avatar;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        mNewUser = ((SignUpActivity) getActivity()).getNewUser();
        mmyAppClient = ((SignUpActivity) getActivity()).getmyAppClient();
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        final View v = inflater.inflate(R.layout.fragment_signup_confirmation, null);

        ((TextView) v.findViewById(R.id.username_textView)).setText(((SignUpActivity) getActivity()).getNewUser().getName());
        avatar = (ImageView) v.findViewById(R.id.avatar);

        if (mNewUser.getAvatarImage() != null) {
            avatar.setImageBitmap(mNewUser.getAvatarImage());
        }


        rotateAnimation = AnimationUtils.loadAnimation(getActivity(), R.anim.progress_rotate);
        v.findViewById(R.id.progress_loading).startAnimation(rotateAnimation);

        if (mNewUser.getAvatarImage() != null) {
            startAvatarUpload();
        } else if (mNewUser.getNewsletter()) {
            setNewsletterStatus();
        } else {
            pauseForOneSecond();
        }

        return v;
    }

    private void startAvatarUpload() {
        mmyAppClient.uploadUserAvatar(mNewUser.getAvatarImage(), new FutureCallback<JsonObject>() {
                    @Override
                    public void onCompleted(Exception e, JsonObject result) {
                        if (mNewUser.getNewsletter()) {
                            setNewsletterStatus();
                        } else {
                            updateFragment();
                        }
                    }
                },
                null,
                null);
    }

    private void setNewsletterStatus() {
        mmyAppClient.setNewsletter(mNewUser.getEmail(), mNewUser.getFirstName(), mNewUser.getLastName(), new FutureCallback<String>() {
            @Override
            public void onCompleted(Exception e, String result) {
                //Log.d(TAG, "Result: " + result);
                updateFragment();
            }
        });
    }

    private void pauseForOneSecond() {
        final Handler handler = new Handler();
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                updateFragment();
            }
        }, 1000);
    }

    private void updateFragment() {
        rotateAnimation.cancel();
        if (isAdded()) {
            getActivity().setResult(Activity.RESULT_OK);
            AnalyticsManager.logUIEvent("sign up completed");
            getActivity().finish();
        } else {
            AnalyticsManager.logUIEvent("sign up failed");
        }

    }
}
Shahbaz Sheikh
  • 404
  • 1
  • 6
  • 15
  • So no rotation huh? `getActivity()` can be null if taps the back button at the right time. – petey Nov 16 '15 at 19:09
  • perhaps the fragments are not being replaced correctly, I suggest that you use fragment transactions to dynamically replace fragments, check this link and let me know if it solves the problem, http://developer.android.com/training/basics/fragments/fragment-ui.html – Dania Nov 16 '15 at 19:12
  • I've disabled the back button because this fragment is where I am POST'ing the new user information to my server. So basically the user sees a loading icon while I am POST'ing their data to the server. Back button is disabled, along with screen rotation, and yet getActivity() still produced NPE. – Shahbaz Sheikh Nov 16 '15 at 19:13
  • @Dania I am dynamically adding fragments. Here is the line of code in my Activity that is updating the container to the fragment which is giving me problems: getFragmentManager().beginTransaction().replace(R.id.container, new SignupConfirmationFragment(), FINAL_FRAGMENT_TAG).commit(); – Shahbaz Sheikh Nov 16 '15 at 19:18
  • Is this line what causing the activity NPE? Or, are you trying to use getActivity()? All of your code for fragment replacement is placed inside a button click event handler, right? – Dania Nov 17 '15 at 11:42
  • @Dania this is the fragment which contains the following code that is causing the NPE: `getActivity().setResult(Activity.RESULT_OK); AnalyticsManager.logUIEvent("sign up completed"); getActivity().finish();` All my code for fragment replacement is triggered by a button click event. – Shahbaz Sheikh Nov 17 '15 at 20:28
  • I think the fragment in which you write this code is detached form its corresponding activity, thus you get NPE. This may be caused by several factors, it is not only screen rotation, as after rotation the activity will be recreated. Maybe you're using these lines before the fragment is being attached to the signup activity. In which method are you writing this getActivity code (onCreateView, onAttach, etc)? Aslo please check this answer http://stackoverflow.com/questions/11536166/android-get-activity-returns-null – Dania Nov 18 '15 at 11:56
  • @Dania I've added the .java file for the fragment that is causing the problems below. Currently I wrapped the problem code in an if(isAdded) to prevent crashing, but I'd still like to figure out the root cause of the problem. – Shahbaz Sheikh Nov 18 '15 at 16:40
  • @ShahbazSheikh, does isAdded solves the problem completely so the app behaves as expected? Or it only avoids the crash and you don't get the output you want? – Dania Nov 18 '15 at 17:37
  • @ShahbazSheikh, I posted an answer, please check it and let me know if it solves the problem. Also, if you want you may remove your code from the answers section and add it to your question as an edit, posting it as an answer indicates that it is the solution. – Dania Nov 18 '15 at 17:52

1 Answers1

5

According to Fragment lifecycle in Android OS, you cannot get the Activity associated with the fragment in the onCreateView, because the Activity with which the Fragment is associated will not be created at that stage.

See the figure below:

enter image description here

Also, refer to this link, http://developer.android.com/guide/components/fragments.html

As you can see the Activity is created in onActivityCreated which is after onCreateView, hence you'll get null if you try to call the Activity in the onCreateView. Try to call it in onActivityCreated or in onStart that should solve your problem.

I hope this helps.

Dania
  • 1,648
  • 4
  • 31
  • 57
  • This diagram is very helpful. I haven't been able to reproduce the bug, but I am fairly certain that I need to reconsider where I am calling getActivity. Also, `isAdded` helps avoid the crash, but doesnt give proper behavior. Thanks again! – Shahbaz Sheikh Nov 18 '15 at 19:07
  • Yes, isAdded will only prevent the crash, it won't solve the problem, because the activity is called before being created. Try to call the activity after its creation, and that should work. You're welcome. – Dania Nov 18 '15 at 19:59
  • Activity State `Created` at the right pictures contains `OnAttach, onCreate, OnCreateView` callbacks: it should only contain `OnActivityCreated` no? – JarsOfJam-Scheduler May 11 '19 at 15:55