14

我正在遷移我的對話框(當前使用Activity.showDialog(DIALOG_ID);)以使用android reference中討論的DialogFragment系統。定位更改時的DialogFragment回調

有使用回調時提供一些事件回活動/片段打開的對話框我的發展過程中產生了一個問題:

這裏有一個簡單的對話框的一些示例代碼:

public class DialogTest extends DialogFragment { 

public interface DialogTestListener { 
    public void onDialogPositiveClick(DialogFragment dialog); 
} 

// Use this instance of the interface to deliver action events 
static DialogTestListener mListener; 

public static DialogTest newInstance(Activity activity, int titleId, int messageId) { 
    udateListener(activity); 
    DialogTest frag = new DialogTest(); 
    Bundle args = new Bundle(); 
    args.putInt("titleId", titleId); 
    args.putInt("messageId", messageId); 
    frag.setArguments(args); 
    return frag; 
} 

public static void udateListener(Activity activity) { 
    try { 
     // Instantiate the NoticeDialogListener so we can send events with it 
     mListener = (DialogTestListener) activity; 
    } catch (ClassCastException e) { 
     // The activity doesn't implement the interface, throw exception 
     throw new ClassCastException(activity.toString() + " must implement DialogTestListener"); 
    } 
} 


@Override 
public Dialog onCreateDialog(Bundle savedInstanceState) { 
    int titleId = getArguments().getInt("titleId"); 
    int messageId = getArguments().getInt("messageId"); 

    AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); 
    // dialog title 
    builder.setTitle(titleId); 
    // dialog message 
    builder.setMessage(messageId); 

    // dialog negative button 
    builder.setNegativeButton("No", new OnClickListener() { 
       public void onClick(DialogInterface dialog, int id) {}}); 
    // dialog positive button 
    builder.setPositiveButton("Yes", new OnClickListener() { 
     public void onClick(DialogInterface dialog, int id) { 
      mListener.onDialogPositiveClick(DialogTest.this); 
     }}); 

    // create the Dialog object and return it 
    return builder.create(); 
}} 

這裏有一些活動代碼叫它:

public class SomeActivity extends FragmentActivity implements DialogTestListener { 
private EditText mUserName; 
@Override 
public void onCreate(Bundle savedInstanceState) { 
    // setup ui 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.ui_user_edit); 
    // name input 
    mUserName = (EditText) findViewById(R.id.userEdit_editTextName); 
} 

@Override 
public void onDialogPositiveClick(DialogFragment dialog) { 
    Log.d(TAG, this.toString()); 
    mUserName.setText(mUserName.getText() + "1"); 
} 

private void showDialog() { 
    DialogTest test = DialogTest.newInstance(SomeActivity.this, R.string.someTitleText, R.string.someMessageText); 
    test.show(getSupportFragmentManager(), "testDialog"); 
}} 

代碼幾乎是你看到的參考。問題是,一旦你做了一個方向改變,當顯示一個對話框時,它會按預期停止工作 - >由於活動的生命週期,活動和對話框都被重建,而對話框現在沒有合適的參考新的重建活動。

我下面的代碼添加到我的activitys的onResume方法:

@Override 
protected void onResume() { 
    super.onResume(); 
    DialogTest.udateListener(this); 
} 

這樣做,我得到預期的行爲,並在對話框發送事件回新改建活動時的方向發生變化。

我的問題是: 什麼是'最佳實踐'來處理由FragmentActivity在方向更改期間打開的DialogFragment之間的回調?

問候

+0

聽起來像你已經倒下了許多片段陷阱。我遇到同樣的問題,因爲我可以在閱讀這篇優秀的文章的同時修復它:http://code.hootsuite.com/orientation-changes-on-android/。 –

回答

6

是的,這是我常常陷入困境的一個常見陷阱。首先讓我說,您在onResume()中調用DialogTest.udateListener()的解決方案似乎完全適合我。

的另一種方法是使用一個ResultReceiver可序列化爲Parcelable

protected void onReceiveResult(int resultCode, Bundle resultData) { 
    if (getActivity() != null){ 
     // Handle result 
    } 
} 

退房ResultReceiver doesn't survire to screen rotation

public class DialogTest extends DialogFragment { 

public static DialogTest newInstance(ResultReceiver receiver, int titleId, int messageId) { 
    DialogTest frag = new DialogTest(); 
    Bundle args = new Bundle(); 
    args.putParcelable("receiver", receiver); 
    args.putInt("titleId", titleId); 
    args.putInt("messageId", messageId); 
    frag.setArguments(args); 
    return frag; 
} 

@Override 
public Dialog onCreateDialog(Bundle savedInstanceState) { 
    int titleId = getArguments().getInt("titleId"); 
    int messageId = getArguments().getInt("messageId"); 
    ResultReceiver receiver = getArguments().getParcelable("receiver"); 

    AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); 
    // dialog title 
    builder.setTitle(titleId); 
    // dialog message 
    builder.setMessage(messageId); 

    // dialog negative button 
    builder.setNegativeButton("No", new OnClickListener() { 
     public void onClick(DialogInterface dialog, int id) { 
      receiver.sendResult(Activity.RESULT_CANCEL, null); 
     }}); 
    // dialog positive button 
    builder.setPositiveButton("Yes", new OnClickListener() { 
     public void onClick(DialogInterface dialog, int id) { 
      receiver.sendResult(Activity.RESULT_OK, null); 
     }}); 

    // create the Dialog object and return it 
    return builder.create(); 
}} 

然後你就可以在接收這樣的處理一切更多細節。所以最終你可能還是需要用Activity重新連線ResultReceiver。唯一的區別是您可以將ActivityDialogFragment分開。

+0

Thx供您參考!現在,我將使用'onResume()'解決方案,一旦我需要一些活動<-> DialogFragment解耦我將看看ResultReceiver。 – darksaga

+2

檢出Fragment#setRetainInstance(boolean)並通讀文檔。這實際上是我們真正想要的解決方案。雖然活動仍在銷燬並重新創建,但片段正在保留並重新使用。因此,回調DialogTestListener仍然指向正確的對象,並且在配置更改後不必重新連接碎片。 –

+0

這個解決方案的問題是,如果你激活「不保留活動」打開對話框,然後按HOME,並從家裏發射器打開App,對話框將被重建,你會得到一個BadParcelableException,我掙扎在這。 – David

-6

另一種方法是,你可以停止活動得到重建。您必須告訴Android您將自行處理方向更改,並且android不會重新創建您的活動。您需要爲您的活動添加到您的清單文件:

android:configChanges="keyboardHidden|orientation" 

如果不是這樣,那麼你可以使用標準的onSaveInstanceState()保存您的狀態,並建議由谷歌恢復使用savedInstanceState

下面是谷歌的官方指南吧: http://developer.android.com/guide/components/activities.html#Lifecycle

通過它,如果你還沒有準備好。它會真正幫助你在android開發中。

+0

我不想停止在定位更改過程中被破壞和重新創建的活動,其在這方面的預期工作。我只想知道處理在定位更改期間由FragmentActivity打開的DialogFragment之間的回調的最佳做法。 – darksaga

1

首先,請致電setTargetFragmentFragmentParent開始dialogFragment。在dialogFragment使用getTargetFragment回調片段並返回數據。所有的數據結果將EXCUTE onactivityresultFragmentParent

的請點擊此鏈接: Receive result from DialogFragment

+0

雖然這是正確的,但它對問題沒有任何作用。因爲數據傳輸和旋轉後恢復回調是不同的事情。例如,在回調中,我可以打開另一個活動或發出請求。 – CoolMind

2

雖然安德烈的解決方案有效,更好的解決方案是在您的FragmentonAttach()得到更新的活動。

private DialogTestListener mListener; 

@Override 
public void onAttach(Activity activity) { 
    super.onAttach(activity); 
    mListener = (DialogTestListener) activity; 
} 

有了這個解決方案,您將不再需要通過在newInstance()Activity了。您只需確保擁有FragmentActivityDialogTestListener。您也不需要像ResultReceiver解決方案那樣保存狀態。

8

有更好的解決辦法,而不是使用靜態方法和變量,因爲它會工作,你的對話框只有來回一個實例。這是更好地回調存儲非靜態成員

private DialogTestListener mListener; 
public void setListener (DialogTestListener listener){ 
    mListener = listener; 
} 

那麼你應該使用TAG這樣mDialogFragment.show(getSupportFragmentManager(), DIALOG_TAG);

,然後在活動onResume方法,你可以重置您的聽衆展示你的對話框

protected void onResume() { 
    super.onResume(); 
    mDialogFragment = (CMFilterDialogFrg) getSupportFragmentManager().findFragmentByTag(DIALOG_TAG); 
    if(mDialogFragment != null){ 
     mDialogFragment.setListener(yourListener) 
    } 
} 
+0

謝謝 - 這種方法適合我!我第一次使用Dialog Fragments進行回調。我在這裏摔跤了一段時間 - 幸好我看到了這篇文章。我幾乎在那裏自己,但這個帖子幫助達到了解決方案+1! –

+0

如果您從活動調用對話框,Jason Long會給出最佳解決方案,如果您從片段調用它,cuasodayleo會提供最佳解決方案,如果您需要面對這兩種情況,這是最佳解決方案。 – natario

相關問題