I’m learning to use Fragment and DialogFragment. As a training I’m trying to extend the AlertDialog example given in the DialogFragment page. Apparently everything is fine: when I show the options menu and click its button a dialog appears and it behaves as expected. However if the configuration changes (for instance when I rotate the screen) while the dialog is displayed then the dialog is recreated properly but clicking any of its buttons crashes the application. I’ve tried lots of things (for instance, static newInstance, setRetainInstance, onSaveInstanceState methods and other documented suggestions) for fixing the problem but nothing seems to work so I’m at the starting point. I’m using support library v4.
This is my main activity code:
public class MainActivity extends FragmentActivity {
private MyDialogFragment dlgf;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
showMyDialog();
return true;
}
private void showMyDialog(){
dlgf = MyDialogFragment.newInstance();
dlgf.show(getSupportFragmentManager(), "dialog");
}
public void doPositive() {
// do stuff...
dlgf.getDialog().dismiss();
}
public void doNegative() {
// Cancel button pressed
dlgf.getDialog().dismiss();
}
}
and this is my DialogFragment code:
public class MyDialogFragment extends DialogFragment {
private View view;
public static MyDialogFragment newInstance() {
MyDialogFragment dlgf = new MyDialogFragment();
return dlgf;
}
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
view = getActivity().getLayoutInflater().inflate(R.layout.alertdialog, null);
return new AlertDialog.Builder(getActivity())
.setView(view)
.setTitle("A Title")
.setPositiveButton("OK",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int buttonID) {
((MainActivity)getActivity()).doPositive();
}
})
.setNegativeButton("Cancel",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int buttonID) {
((MainActivity)getActivity()).doNegative();
}
})
.create();
}
}
When the execution crashes after clicking the Cancel button the logcat shows a NullPointerException in the doNegative method. If the crash occurs after clicking the OK button then the NullPointerException occurs in the doPositive method. It seems clear that the DialogFragment object is null.
Could someone help me, please? TIA
The
Activityinstance that originally setdlgfinshowMyDialog()is destroyed upon configuration change and a new one is created. That new one does not havedlgfset so you get the NPE.getActivity()inside aFragmentwill return you the current activity instance theFragmentis attached to. In your case it will correctly call the method in the fresh instance.To solve your problem you could simply pass the
Fragmentthat caused the callback to yourActivityso you don’t have to store a reference to it.Another possibility is to let your
Activityretain the reference to itsMyDialogFragmentusingonRetainNonConfigurationInstance()/getLastNonConfigurationInstance().