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

このコードは、参考になるものです。問題は、いったんオリエンテーションを変更すると、ダイアログが表示され、期待どおりに動作しなくなることです。>アクティビティのライフサイクルのために、アクティビティとダイアログが再構築され、ダイアログに適切な新しい再構築されたアクティビティへの参照。私は予想される動作を取得し、姿勢の変化が発生したときにダイアログが新たに再構築された活動に戻ってイベントを送信し、これを実行

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

は、私は私のactivitysにonResumeメソッドを次のコードを追加しました。

質問: オリエンテーションの変更中にFragmentActivityによって開かれたDialogFragment間のコールバックを処理するための「ベストプラクティス」とは何ですか?

お礼

+0

あなたが1つ多くの断片の落とし穴に倒れたような音。私はあなたと同じ問題を抱えていました。この優れた記事http://code.hootsuite.com/orientation-changes-on-android/を読んでいる間に修正することができました。 –

答えて

6

これは一般的なトラップです。私はいつも自分の中に落ちています。まず最初に、DialogTest.udateListener()onResume()にあなたの解決策が私にとって完全に適切であると思わせてください。

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

別の方法は、ParcelableとしてシリアライズすることができResultReceiverを使用することです詳細はこちらですから、最後にはActivityResultReceiverを再配線する必要があります。唯一の違いは、をDialogFragmentから分離することです。

+0

Thx!今のところ私はいくつかのアクティビティが必要になったら、 'onResume()'ソリューションを使用します。<-> DialogFragmentデカップリング私はResultReceiverを見ていきます。 – darksaga

+2

Fragment#setRetainInstance(boolean)をチェックし、ドキュメントを読んでください。これは実際に私たちが本当に求めている解決策です。アクティビティがまだ破棄され再作成されている間、そのフラグメントは保持され、再利用されています。したがって、コールバックのDialogTestListenerは引き続き正しいオブジェクトを指し示しているため、構成の変更後にフラグメントを再配線する必要はありません。 –

+0

このソリューションの問題点は、「アクティビティを保持しないでください」をアクティブにしてダイアログを開き、HOMEを押してホームランチャーからアプリケーションを開くと、ダイアログが再作成され、BadParcelableExceptionが発生することです。これに。 – David

-6

別の方法として、アクティビティを再作成することをやめることができます。あなたはあなた自身がオリエンテーションの変更を処理することをAndroidに伝えなければなりません。アンドロイドはあなたの活動を再現しません。あなたのマニフェストファイルへのあなたの活動のためにこれを追加する必要があります。

android:configChanges="keyboardHidden|orientation" 

がないこの場合、あなたはあなたの状態を保存し、Googleが推奨するようsavedInstanceStateを使用して回復する標準onSaveInstanceState()を使用することができます。ここで

はそれのためのGoogleの公式ガイドです: http://developer.android.com/guide/components/activities.html#Lifecycle

お持ちでない場合は、それを通過します。それは本当にあなたのアンドロイド開発に役立ちます。

+0

私はオリエンテーションの変更中に破壊されたり再現された活動を止めたいと考えていません。オリエンテーションの変更中にFragmentActivityによって開かれたDialogFragment間のコールバックを処理するベストプラクティスを知りたいだけです。入力のための – darksaga

1

setTargetFragmentFragmentParentからdialogFragmentに最初に呼び出します。 dialogFragmentでは、フラグメントをコールバックしてデータを返すためにgetTargetFragmentを使用します。 Receive result from DialogFragment

+0

これは間違いありませんが、何の問題もありません。回転後のデータの転送とコールバックの復元は異なるためです。たとえば、コールバックでは別のアクティビティを開くか、リクエストを行うことができます。 – CoolMind

2

アンドレのソリューションは動作しますが、より良い解決策は、あなたのFragmentonAttach()中に更新活動を得ることです:すべてのデータの結果は、このリンクをたどっonactivityresult

FragmentParentのでexcuteます。このソリューションで

private DialogTestListener mListener; 

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

、あなたはもうnewInstance()Activityを渡す必要はありません。 Fragmentを所有するActivityDialogTestListenerであることを確認するだけです。また、ResultReceiverのように状態を保存する必要はありません。

8

静的メソッドと変数を使用する代わりに、ダイアログの1つのインスタンスだけが機能するため、より良い解決策があります。その後

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

あなたがあなたの活動のonResume方法では、あなたのリスナーリセットすることができ、このmDialogFragment.show(getSupportFragmentManager(), DIALOG_TAG);

などタグを使用して、ダイアログを表示する必要があります非静的メンバーとして、あなたのコールバックを保存することをお勧めし

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

関連する問題