Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Retaining listener after screen rotation - DialogFragment with DatePicker

When clicking an EditText field in my (Scherlock)FragmentActivity a DatePicker shows up. After selecting date and clicking "apply" the Edittext field is populated with the date. This works fine until i rotate the screen while the DatePicker is visible. Its onCreateDialog-method starts again an everything looks right. But when I click "apply" no date is filled in to the EditText field.

This is most likely because I haven't managed to retain the listener. This problem is very similar to DialogFragment - retaining listener after screen rotation However in my code I have a listener interface included in the DialogFragment and I cannot manage to reach the listener from the calling FragmentActivity, (as the solution suggests in the mentioned question).

  • I suppose not, but is there a way to save a listener before the activity is destroyed? (I'm not interested in the Manifest modification.)
  • Is there a way to modify this DialogFragment or is this solution with included interface not suitable in this case?

Please help me, this really shouldn't be that hard but I've been working with it for longer than I will admit...

Here is the DialogFragment code:

public class DateDialogFragment extends SherlockDialogFragment {    

public static String TAG = "DateDialogFragment";
static Context mContext; 
static int mYear;
static int mMonth;
static int mDay;
static DateDialogFragmentListener mListener;


public static DateDialogFragment newInstance(Context context, DateDialogFragmentListener listener, Calendar now) {
    DateDialogFragment dialog = new DateDialogFragment();
    mContext = context;
    mListener = listener;       
    mYear = now.get(Calendar.YEAR);
    mMonth = now.get(Calendar.MONTH);
    mDay = now.get(Calendar.DAY_OF_MONTH);      
    return dialog;
}


public Dialog onCreateDialog(Bundle savedInstanceState) {
    return new DatePickerDialog(mContext, mDateSetListener, mYear, mMonth, mDay);
}


private OnDateSetListener mDateSetListener = new OnDateSetListener() {      
    @Override
    public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth) {
        mYear = year;
        mMonth = monthOfYear;
        mDay = dayOfMonth;          
        mListener.updateChangedDate(year, monthOfYear, dayOfMonth);
    }
};


public interface DateDialogFragmentListener {
    public void updateChangedDate(int year, int month, int day);
}

}

Edit: Here is a piece of my FragmentActivity: the method I use to call the DialogFragment:

public void showDatePickerDialog() {    
    now = Calendar.getInstance();   
    DateDialogFragment frag = DateDialogFragment.newInstance(
            this, new DateDialogFragment.DateDialogFragmentListener() {
        public void updateChangedDate(int year, int month, int day) {
            birthdate.setText(String.valueOf(day) + "-" + String.valueOf(month+1) + "-" +  String.valueOf(year));                               
            now.set(year, month, day);
            pet.setBirthdate(birthdate.getText().toString());
        }
    }, 
    now);
    frag.show(getSupportFragmentManager(), "DateDialogFragment");   
}   
like image 560
Christina Avatar asked Dec 16 '22 05:12

Christina


2 Answers

I came across the same issue. And here is the solution, from Luksprog. It works perfectly for me.

if (savedInstanceState != null) {
    DatePickerFragment dpf = (DatePickerFragment) getSupportFragmentManager()
            .findFragmentByTag("theTag?");
    if (dpf != null) {
        dpf.setListener(listener);
    }
}

And no need to parcel the fragment as mentioned in above answers...

like image 189
Ashokchakravarthi Nagarajan Avatar answered Dec 31 '22 12:12

Ashokchakravarthi Nagarajan


With help from a friend I now have a solution to this problem. The short version is: Make the DateDialogFragment parcelable and save the fragment on orientation change. Recreate the listener every time onCreate in the calling class runs. As you can see the showDatePickerDialog() is changed so that the creation of the listener is moved out of it.

Here are some snippets, starting with the calling class:

DateDialogFragment frag;
DateDialogFragment.DateDialogFragmentListener mListener;
private EditText birthdate;
private Calendar now;

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

    mListener = new DateDialogFragment.DateDialogFragmentListener() {
        @Override
        public void updateChangedDate(int year, int month, int day) {                               
            now.set(year, month, day);
            pet.setBirthdate(now.getTimeInMillis());
            birthdate = (EditText) findViewById(R.id.birth_day_et);     
            birthdate.setText(pet.getBirthdateInText());
        }
    };  

    if (savedInstanceState != null) {   
        pet.setBirthdate(savedInstanceState.getLong("birthday"));           
        now = (Calendar) savedInstanceState.getSerializable("n");
        if (now != null) {
            frag = (DateDialogFragment) savedInstanceState.getParcelable("frag");
            frag.setListener(mListener);                
        }
    } 

@Override
protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
        outState.putLong("birthday", pet.getBirthdateInMillis());
        outState.putSerializable("n", now);
        outState.putParcelable("frag", frag);           
    }
}

public void showDatePickerDialog() {    
    now = Calendar.getInstance();   
    frag = DateDialogFragment.newInstance(this, mListener, now);
    frag.show(getSupportFragmentManager(), "DateDialogFragment");   
}   

And here are the changes to the DateDialogFragment class. Except from what's written below the class looks the same as in my question.

public class DateDialogFragment extends SherlockDialogFragment implements Parcelable {

@Override
public int describeContents() {
    return 0;
}

@Override
public void writeToParcel(Parcel arg0, int arg1) {      
}

public static void setListener(DateDialogFragmentListener listener) {
    mListener = listener;
}

The solution to recreate the listener in the calling class may not be the prettiest possible but at least it works. I hope this will be useful to someone. :)

like image 40
Christina Avatar answered Dec 31 '22 14:12

Christina