Android: Fragment manager becomes null
Asked Answered
J

4

9

I am getting crashes for my app. Basically, I have a fragment in which a dialog has to be displayed in one scenario. I had created dialog by extending dialog fragment. The problem is for some users it crashes throwing null pointer exception. This is the snippet of dialog:

VerifyOTPDialog verifyOTPDialog = VerifyOTPDialog.newInstance("Kindly Enter the OTP sent to your Registered Mobile No. :", false, "Verify & Proceed",
                    "home_screen");
verifyOTPDialog.show(getFragmentManager(), VerifyOTPDialog.class.getSimpleName());

The app crashes at the 2nd line. From crashlytics,I got the following stack trace:

Fatal Exception: java.lang.NullPointerException: Attempt to invoke virtual method 'android.app.FragmentTransaction android.app.FragmentManager.beginTransaction()' on a null object reference
   at android.app.DialogFragment.show(DialogFragment.java:228)
   at in.droom.fragments.HomeScreenFragment.updateUI(HomeScreenFragment.java:553)
   at in.droom.fragments.HomeScreenFragment.onResponse(HomeScreenFragment.java:626)
   at in.droom.fragments.HomeScreenFragment.onResponse(HomeScreenFragment.java:100)
   at in.droom.util.DroomApi$1.onPostExecute(DroomApi.java:1136)
   at in.droom.util.DroomApi$1.onPostExecute(DroomApi.java:1094)
   at android.os.AsyncTask.finish(AsyncTask.java:636)
   at android.os.AsyncTask.access$500(AsyncTask.java:177)
   at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:653)
   at android.os.Handler.dispatchMessage(Handler.java:111)
   at android.os.Looper.loop(Looper.java:194)
   at android.app.ActivityThread.main(ActivityThread.java:5637)
   at java.lang.reflect.Method.invoke(Method.java)
   at java.lang.reflect.Method.invoke(Method.java:372)
   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:959)
   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:754)

0. Crashed: main: 0 0 0x0000000000000000

   at android.app.DialogFragment.show(DialogFragment.java:228)
   at in.droom.fragments.HomeScreenFragment.updateUI(HomeScreenFragment.java:553)
   at in.droom.fragments.HomeScreenFragment.onResponse(HomeScreenFragment.java:626)
   at in.droom.fragments.HomeScreenFragment.onResponse(HomeScreenFragment.java:100)
   at in.droom.util.DroomApi$1.onPostExecute(DroomApi.java:1136)
   at in.droom.util.DroomApi$1.onPostExecute(DroomApi.java:1094)
   at android.os.AsyncTask.finish(AsyncTask.java:636)
   at android.os.AsyncTask.access$500(AsyncTask.java:177)
   at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:653)
   at android.os.Handler.dispatchMessage(Handler.java:111)
   at android.os.Looper.loop(Looper.java:194)
   at android.app.ActivityThread.main(ActivityThread.java:5637)
   at java.lang.reflect.Method.invoke(Method.java)
   at java.lang.reflect.Method.invoke(Method.java:372)
   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:959)
   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:754)

As far as I understood, the fragment manager became null at some point of time. But, I am unable to reproduce the scenario. The crashes are happening to no. of users almost everyday.

Update: (VerifyOtpDialog)

public class VerifyOTPDialog extends DialogFragment implements OnClickListener {
private static final String TAG_NAME = VerifyOTPDialog.class.getSimpleName();
private Context ctx;
private Dialog dialog;
private boolean isLaterVisible;
private String strTitle, strBtnTitle, strFragment = "";

private BroadcastReceiver broadcastReceiver;
private ProfileAddressContactInfoModel userModel;
private VerifyOTPDialogDismissed verifyOTPDialogDismissed;
public static final String RECEIVE_OTP = "com.myapp.ACTION_RECEIVED";

private ImageView imgViewForClose;
private RobotoRegularEditTextView editTextForOTP;
private RobotoBoldTextView btnLater, btnVerifyAndProceed;
private RobotoLightTextView txtViewForTitle, txtViewForResendOTP;
public popFragmentListener mPopFragmentListener;

public VerifyOTPDialog() {

}

public static VerifyOTPDialog newInstance(String strTitle, boolean isLaterVisible, String strBtnTitle, String strFragment) {
    VerifyOTPDialog dialog = new VerifyOTPDialog();
    Bundle b = new Bundle();
    b.putString("title", strTitle);
    b.putBoolean("isLaterVisible", isLaterVisible);
    b.putString("btnTitle", strBtnTitle);
    b.putString("strFrom", strFragment);
    dialog.setArguments(b);
    return dialog;
}

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    ctx = getActivity();
    registerReceiver();
}

@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
    dialog = super.onCreateDialog(savedInstanceState);
    dialog.setOnKeyListener(new OnKeyListener() {
        @Override
        public boolean onKey(android.content.DialogInterface dialog, int keyCode, android.view.KeyEvent event) {
            if ((keyCode == android.view.KeyEvent.KEYCODE_BACK)) {
                AppUtil.hideKeyboard();
                return true;
            } else
                return false;
        }
    });

    return dialog;
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.verify_otp_popup, container, false);
    Bundle b = getArguments();
    strTitle = b.getString("title");
    isLaterVisible = b.getBoolean("isLaterVisible");
    strBtnTitle = b.getString("btnTitle");
    strFragment = b.getString("strFrom");
    getDialog().setCanceledOnTouchOutside(false);
    getDialog().getWindow().requestFeature(Window.FEATURE_NO_TITLE);
    getDialog().getWindow().setBackgroundDrawable(new ColorDrawable(0));

    userModel = AppUtil.getUserProfile();

    imgViewForClose = (ImageView) view.findViewById(R.id.imgViewForClose);
    editTextForOTP = (RobotoRegularEditTextView) view.findViewById(R.id.editTextForOTP);
    btnLater = (RobotoBoldTextView) view.findViewById(R.id.btnLater);
    btnVerifyAndProceed = (RobotoBoldTextView) view.findViewById(R.id.btnVerifyAndProceed);
    txtViewForTitle = (RobotoLightTextView) view.findViewById(R.id.txtViewForTitle);
    txtViewForResendOTP = (RobotoLightTextView) view.findViewById(R.id.txtViewForResendOTP);

    if (userModel != null)
        txtViewForTitle.setText(strTitle + " +91 " + userModel.getContactInfo().getMobilePhone());

    txtViewForResendOTP.setText(getUnderlinedContent());

    if (!isLaterVisible)
        btnLater.setVisibility(View.GONE);

    btnVerifyAndProceed.setText(strBtnTitle);

    imgViewForClose.setOnClickListener(this);
    txtViewForResendOTP.setOnClickListener(this);
    btnLater.setOnClickListener(this);
    btnVerifyAndProceed.setOnClickListener(this);

    return view;
}

public interface VerifyOTPDialogDismissed {
    void dialogDismissing(String... s);
}

@Override
public void onDismiss(DialogInterface dialog) {
    super.onDismiss(dialog);
}

public VerifyOTPDialogDismissed getDialogDismissListener() {
    return verifyOTPDialogDismissed;
}

public void setDialogDismissListener(VerifyOTPDialogDismissed VerifyOTPDialogDismissed) {
    this.verifyOTPDialogDismissed = VerifyOTPDialogDismissed;
}

private void registerReceiver() {
    IntentFilter intentFilter = new IntentFilter();
    intentFilter.addAction(RECEIVE_OTP);

    broadcastReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            String strOTP = intent.getExtras().getString("otp");

            if (strOTP != null && editTextForOTP != null)
                editTextForOTP.setText(strOTP);
        }
    };

    ctx.registerReceiver(broadcastReceiver, intentFilter);
}

private SpannableString getUnderlinedContent() {
    SpannableString content = new SpannableString(getResources().getString(R.string.resend_otp));
    content.setSpan(new UnderlineSpan(), 0, content.length(), 0);
    content.setSpan(new ForegroundColorSpan(getResources().getColor(R.color.blue_button)), 0, content.length(), 0);
    return content;
}

private void sendOTP(HashMap<String, String> params) {
    Response.Listener<JSONObject> responseListener = new Response.Listener<JSONObject>() {
        @Override
        public void onResponse(JSONObject response) {
            try {
                Logger.debugMessage("Response Object", response.toString());
                String responseCode = response.getString("code");

                if (responseCode.equalsIgnoreCase("success")) {
                    String message = response.getString("message");
                    Toast.makeText(ctx, message, Toast.LENGTH_SHORT).show();
                } else if (responseCode.equalsIgnoreCase("failed")) {
                    if (response.has("error")) {
                        if (response.has("error_code")) {
                            String error_code = response.optString("error_code");
                            displayMessageAlert(response.optString("error"), "", error_code);
                        } else {
                            displayMessageAlert(response.optString("error"), "", "");
                        }
                    } else if (response.has("errors")) {
                        JSONArray errorsArray;
                        try {
                            errorsArray = response.getJSONArray("errors");
                            Toast.makeText(ctx, errorsArray.getString(0), Toast.LENGTH_SHORT).show();
                        } catch (JSONException e) {
                            e.printStackTrace();
                        }
                    }
                }
            } catch (JSONException e) {
                e.printStackTrace();
            }
        }
    };

    Response.ErrorListener errorListener = new Response.ErrorListener() {
        @Override
        public void onErrorResponse(VolleyError error) {

        }
    };

    Api.sendOTP(params, responseListener, errorListener);
}

private void verifyOTP(HashMap<String, String> params, final String strFragment) {
    Response.Listener<JSONObject> responseListener = new Response.Listener<JSONObject>() {
        @Override
        public void onResponse(JSONObject response) {
            try {
                Logger.debugMessage("Response Object", response.toString());
                String responseCode = response.getString("code");

                if (responseCode.equalsIgnoreCase("success")) {
                    if (userModel != null) {
                        userModel.setPhoneVerified(true);
                        userModel.setOTPVerified(true);
                        AppUtil.saveUserProfile(userModel);
                    }

                    VerifyOTPDialog.this.dismissAllowingStateLoss();
                    String event_name = "";
                    if (strFragment.equalsIgnoreCase("SellFragment")) {
                        event_name = "otp_verified_on_sell";
                        MainActivity.getInstance().pushFragment(SellFragment.newInstance(), SellFragment.class.getSimpleName(), true);
                    } else if (strFragment.equalsIgnoreCase("QuickSellFragment")) {
                        event_name = "otp_verified_on_quick_sell";
                        MainActivity.getInstance().pushFragment(new QuickSellFragment(), QuickSellFragment.class.getSimpleName(), true);
                    } else if (strFragment.equalsIgnoreCase("gotoPaymentFlow")) {
                        event_name = "otp_verified_on_payment";
                        DraftSummaryFragment.getInstance().gotoPaymentFlow();
                    } else if (strFragment.equalsIgnoreCase("gotoPlaceBidPage")) {
                        event_name = "otp_verified_on_place_bid";
                        verifyOTPDialogDismissed.dialogDismissing(strFragment);
                    } else if (strFragment.equalsIgnoreCase("make_best_offer")) {
                        event_name = "otp_verified_on_make_best_offer";
                        verifyOTPDialogDismissed.dialogDismissing(strFragment);
                    } else if (strFragment.equalsIgnoreCase("checkAvailableFees")) {
                        event_name = "otp_verified_on_quick_sell";
                        QuickSellDraftSummaryFragment.getInstance().checkAvailableFees();
                    } else if (strFragment.equalsIgnoreCase("home_screen")) {
                        event_name = "otp_verified_for_casual_seller";
                    } else if (strFragment.equalsIgnoreCase("my_profile")) {
                        event_name = "otp_verified_from_my_profile";
                    } else if (strFragment.equalsIgnoreCase("my_profile")) {
                        event_name = "otp_verified_from_my_profile";
                    } else if (strFragment.equalsIgnoreCase("pro_seller_profile_settings")) {
                        event_name = "otp_verified_from_pro_seller_profile_settings";
                    } else if (strFragment.equalsIgnoreCase("pro_seller_welcome")) {
                        event_name = "otp_verified_from_pro_seller_welcome";
                    } else if (strFragment.equalsIgnoreCase("seller_badges")) {
                        event_name = "otp_verified_from_seller_badges";
                    } else if (strFragment.equalsIgnoreCase("trust_factor")) {
                        event_name = "otp_verified_from_trust_factor";
                    } else if (strFragment.equalsIgnoreCase("ProSellerDashboard"))
                        MainActivity.getInstance().pushFragment(ProSellerDashboardFragment.newInstance(false), ProSellerDashboardFragment.class.getSimpleName(), true);
                    else
                        event_name = "otp_verified_from_my_account";

                    JSONObject post = BetaOutAPIs.getPostDataForUserAdd(userModel, "update");
                    JSONArray eventArray = new JSONArray();
                    JSONObject event = new JSONObject();
                    event.put("name", event_name);
                    event.put("timestamp", String.valueOf(System.currentTimeMillis() / 1000));
                    eventArray.put(event);
                    post.put("events", eventArray);
                    BetaOutAPIs.sendEventToBetaOut(post, TAG_NAME);
                    BaseApplication.getInstance().trackMoEngageEvents(event_name, new PayloadBuilder().build());
                } else if (responseCode.equalsIgnoreCase("failed")) {
                    btnVerifyAndProceed.setEnabled(true);
                    if (response.has("error")) {
                        if (response.has("error_code")) {
                            String error_code = response.optString("error_code");
                            displayMessageAlert(response.optString("error"), "", error_code);
                        } else {
                            displayMessageAlert(response.optString("error"), "", "");
                        }
                    } else if (response.has("errors")) {
                        Toast.makeText(ctx, response.optString("errors"), Toast.LENGTH_SHORT).show();
                    }
                }
            } catch (JSONException e) {
                e.printStackTrace();
            }
        }
    };

    Response.ErrorListener errorListener = new Response.ErrorListener() {
        @Override
        public void onErrorResponse(VolleyError error) {
            error.printStackTrace();
        }
    };

    Api.verifyOTP(params, responseListener, errorListener);
}

private boolean validateOTP() {
    String validationMessage = "";
    boolean isValid = true;
    String email = editTextForOTP.getText().toString();

    if (email.length() == 0) {
        isValid = false;
        validationMessage = "Please Enter OTP";
        Toast.makeText(getActivity(), validationMessage, Toast.LENGTH_SHORT).show();
    }

    return isValid;
}

@Override
public void onClick(View v) {
    switch (v.getId()) {
        case R.id.imgViewForClose:
            VerifyOTPDialog.this.dismissAllowingStateLoss();
            break;

        case R.id.txtViewForResendOTP:
            if (userModel != null) {
                HashMap<String, String> params = new HashMap<String, String>();
                params.put("user_id", AppSharedPref.getUserId());
                params.put("phone", userModel.getContactInfo().getMobilePhone());
                sendOTP(params);
            }
            break;

        case R.id.btnLater:
            VerifyOTPDialog.this.dismissAllowingStateLoss();

            if (mPopFragmentListener != null)
                mPopFragmentListener.gotoRootFragment();
            if (strFragment.equalsIgnoreCase("SellFragment")) {
                       MainActivity.getInstance().pushFragment(SellFragment.newInstance(), SellFragment.class.getSimpleName(), true);
            } else if (strFragment.equalsIgnoreCase("QuickSellFragment")) {
                MainActivity.getInstance().pushFragment(new QuickSellFragment(), QuickSellFragment.class.getSimpleName(), true);
            } else if (strFragment.equalsIgnoreCase("gotoPlaceBidPage")) {
                //verifyOTPDialogDismissed.dialogDismissing();
            } else if (strFragment.equalsIgnoreCase("ProSellerDashboard"))
                         MainActivity.getInstance().pushFragment(ProSellerDashboardFragment.newInstance(false), ProSellerDashboardFragment.class.getSimpleName(), true);
            break;

        case R.id.btnVerifyAndProceed:
            if (validateOTP()) {
                btnVerifyAndProceed.setEnabled(false);
                HashMap<String, String> map = new HashMap<String, String>();
                map.put("user_id", SharedPref.getUserId());
                map.put("code", editTextForOTP.getText().toString());
                verifyOTP(map, strFragment);
            }
            break;

        default:
            break;
    }
}

protected void displayMessageAlert(String message, String title, final String error_code) {
    String s = "Alert";
    if (title != null && title.length() > 0) {
        s = title;
    }

    if (message != null) {
        new AlertDialog.Builder(ctx).setTitle(s).setMessage(message)
                .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int which) {
                        if (error_code.toLowerCase().equals("logout")) {
                            AppUtil.logoutUser((MainActivity) ctx);
                            MainActivity.getInstance().pushFragment(LoginFragment.newInstance(true, true), LoginFragment.class.getSimpleName(), true);
                        }
                        dialog.dismiss();
                    }
                }).show();
    }
}

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

    if (broadcastReceiver != null) {
        ctx.unregisterReceiver(broadcastReceiver);
    }
}

public void setPopFragmentListener(popFragmentListener mPopFragmentListener) {
    this.mPopFragmentListener = mPopFragmentListener;
}

public interface popFragmentListener {
    void gotoRootFragment();
}
}
Josey answered 25/7, 2016 at 13:10 Comment(10)
can you please put your VerifyOTPDialog hereStores
Are you calling show() in fragment?Revanchism
Do you call show inside async-task?Tremblay
@VishalPatoliya Posted VerifyOTPDialog. Please have a lookJosey
@g4s8 I am not calling show in asynctaskJosey
@AkshayBhat Yes I am calling show over dialog from fragmentJosey
You are using v4 or appFragment??Stores
@VishalPatoliya I am using android.app.FragmentJosey
can you tried to remove this @Override public Dialog onCreateDialog(Bundle savedInstanceState)Stores
Ok I'll try and let you know the result. The biggest problem is we are unable to figure out when this happens.Josey
S
4

You should get the fragment manager before :

FragmentManager fragMan = getSupportFragmentManager();

then test it's nullity

if(fragMan != null){
    // Do stuff
}

And if you are using if in DoInBackground of the asynctask you should get the Uithread :

runOnUiThread(new Runnable() {
    public void run() {
        // do stuff on the ui like display fragments
    }
});

EDIT :

You should use the support v4 library for supporting fragment

Sitka answered 25/7, 2016 at 13:53 Comment(0)
W
2

If you are showing from Fragment, then use getChildFragmentManager() :

Like :

verifyOTPDialog.show(getChildFragmentManager(),VerifyOTPDialog.class.getSimpleName());
Wera answered 26/7, 2016 at 6:14 Comment(2)
But that is available from API 17. Also I am using android.app.fragmentJosey
Then you have to use android.support.v4.app.dialogFragment for DialogFragment and for the fragment use android.support.v4.app.Fragment. You have to extend FragmentActivity or AppCompatActivity in your Activity. This way you can get getchildFragmentManager() in Fragment below api 17.Revanchism
M
1

You said you are using android.app.fragment to host your fragment. Since you are making the dialog using android DialogFragment, the dialog Fragment itself is a fragment, thus making this a case of nested Fragments in android. When we nest frgaments we use getChildFragmentManager().

The Support for nested fragments in android was not available in API 11. The support for nested Fragments started from API 17 and onwards. If you want to use nested Fragments in API 11 - 16, then you have to use the support library fragments.

So you have to make your DialogFragment of type android.support.v4.app.dialogFragment and your fragment of type android.support.v4.app.fragment

Messenger answered 3/8, 2016 at 21:3 Comment(0)
W
0

I would recommend calling the DialogFragment from the parent activity so that you don't run into issues with the fragment lifecycle. Since you are probably trying to have the fragments communicate with each other, that should be done through the Activity.

Here is more information - https://developer.android.com/training/basics/fragments/communicating.html

Following the steps:

  1. Define the interface
  2. Implement the interface
  3. Deliver a Message to a Fragment

The last step is where you can call the DialogFragment and then have the Dialog return the data back the activity and then pass it to the calling Fragment.

Wrest answered 5/8, 2016 at 23:6 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.