屏幕旋转后保留监听者 - 带有DatePicker的DialogFragment

4
当我在我的(Scherlock)FragmentActivity中单击EditText字段时,会显示一个DatePicker。选择日期并点击“应用”后,Edittext字段将填充日期。这很好用,直到我旋转屏幕时DatePicker可见。它的onCreateDialog方法重新启动,一切看起来都没问题。但是当我点击“应用”时,没有日期填写到EditText字段中。
这很可能是因为我没有成功保留侦听器。这个问题非常类似于DialogFragment - retaining listener after screen rotation ,但是在我的代码中,我在DialogFragment中包含了一个侦听器接口,并且我无法从调用的FragmentActivity中访问该侦听器(如所提出的解决方案所建议的那样)。
  • 我认为不行,但是在活动被销毁之前有保存侦听器的方法吗?(我对清单修改不感兴趣。)
  • 有没有办法修改这个DialogFragment,或者这种包含接口的解决方案在这种情况下不适用?
请帮帮我,这真的不应该那么难,但我已经处理了比我愿意承认的时间...
以下是DialogFragment代码:
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);
}

}

编辑:这是我FragmentActivity的一部分:我用来调用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");   
}   

覆盖 onSaveInstanceState 并使用 bundle outState.putString("key1", editextvalue),然后在 onActivityCreated 中使用以下代码 if( savedInstanceState!=null) { editextvalue = savedInstanceState.getString("key1")}。现在将此内容用于设置到editext中。 - Raghunandan
谢谢,但是在屏幕旋转后我已经可以看到我的选择日期在日期选择器中了。即使没有使用onSaveInstanceState,信息也会传递到调用FragmentActivity中showDatePickerDialog()内的updateChangedDate()方法中。(我已经测试过并且可以验证该方法内的EditText获取了值。)问题是它从未更新GUI。监听器消失了,对吧? - Christina
那么问题是什么?如果您看到所选日期,则使用监听器将其设置为EditText。 - Raghunandan
问题在于我只能在updateChangedDate()函数中看到我选择的日期。我可以通过System.out.println来查看。没有屏幕旋转,下面的第一行将更新我的EditText(名为birthdate)。 birthdate.setText(String.valueOf(day) + "-" + String.valueOf(month+1) + "-" + String.valueOf(year)); System.out.println("在showDatePickerDialog中 - updateChangedDate()函数。birthdate: " + birthdate.getText().toString()); - Christina
2个回答

8

我遇到了相同的问题。这里是解决方案,来自Luksprog。它对我完美地起作用。

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

无需像上面的答案中提到的那样将片段封装起来...

m0ds是什么,它来自哪里? - danijoo
这只是日期选择器监听器。我已经更新了我的回答。@danijoo - Ashokchakravarthi Nagarajan
如果我的监听器不是另一个片段,而是一个Presenter呢? - frankelot

4
通过朋友的帮助,我现在有了解决这个问题的方法。简短地说:将DateDialogFragment转换为可包含在Parcel中的Parcelable对象,并在屏幕方向更改时保存该对象。每次调用类中的onCreate时重新创建监听器。正如您所看到的,showDatePickerDialog()已更改,以便将侦听器的创建移到外部。
下面是一些代码片段,从调用类开始:
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");   
}   

以下是DateDialogFragment类的更改内容。除下面所写之外,该类与我的问题中的相同。

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;
}

重新在调用类中创建监听器的解决方案可能不是最优美的解决方案,但至少它能够工作。希望这对某些人有用。 :)


2
你实际上不需要使其可解析。你可以使用片段管理器的putFragment()将对片段的引用放入bundle中,例如savedInstanceState和outState。 - Hirschen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接