アクティビティの再起動時に、アラートビルダーで作成されたダイアログが消えないようにしようとしています。
OnConfigurationChangedメソッドをオーバーロードすると、これを正常に実行してレイアウトを正しい方向にリセットできますが、edittextのスティッキーテキスト機能が失われます。したがって、ダイアログの問題を解決する際に、この編集テキストの問題を作成しました。
編集テキストから文字列を保存し、onCofigurationの変更で文字列を再割り当てしても、回転前に入力された値ではなく、初期値がデフォルトのままであるように見えます。無効化を強制しても、それらは更新されるようです。
ダイアログの問題か、テキストの編集の問題を解決する必要があります。
助けてくれてありがとう。
最近この問題を回避する最善の方法は、 DialogFragment
を使用することです。
DialogFragment
を拡張する新しいクラスを作成します。 onCreateDialog
をオーバーライドして、古い Dialog
または AlertDialog
を返します。
次に、 DialogFragment.show(fragmentManager, tag)
で表示できます。
Listener
の例を次に示します。
public class MyDialogFragment extends DialogFragment {
public interface YesNoListener {
void onYes();
void onNo();
}
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
if (!(activity instanceof YesNoListener)) {
throw new ClassCastException(activity.toString() + " must implement YesNoListener");
}
}
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
return new AlertDialog.Builder(getActivity())
.setTitle(R.string.dialog_my_title)
.setMessage(R.string.dialog_my_message)
.setPositiveButton(Android.R.string.yes, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
((YesNoListener) getActivity()).onYes();
}
})
.setNegativeButton(Android.R.string.no, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
((YesNoListener) getActivity()).onNo();
}
})
.create();
}
}
そして、あなたが呼び出すアクティビティで:
new MyDialogFragment().show(getSupportFragmentManager(), "tag"); // or getFragmentManager() in API 11+
この回答は、これらの他の3つの質問(およびその回答)の説明に役立ちます。
// Prevent dialog dismiss when orientation changes
private static void doKeepDialog(Dialog dialog){
WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
lp.copyFrom(dialog.getWindow().getAttributes());
lp.width = WindowManager.LayoutParams.WRAP_CONTENT;
lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
dialog.getWindow().setAttributes(lp);
}
public static void doLogout(final Context context){
final AlertDialog dialog = new AlertDialog.Builder(context)
.setIcon(Android.R.drawable.ic_dialog_alert)
.setTitle(R.string.titlelogout)
.setMessage(R.string.logoutconfirm)
.setPositiveButton("Yes", new DialogInterface.OnClickListener()
{
@Override
public void onClick(DialogInterface dialog, int which) {
...
}
})
.setNegativeButton("No", null)
.show();
doKeepDialog(dialog);
}
AndroidManifest.xmlのアクティビティ要素にAndroid:configChanges = "orientation"を追加するだけです
例:
<activity
Android:name=".YourActivity"
Android:configChanges="orientation"
Android:label="@string/app_name"></activity>
向きの変更時にレイアウトを変更する場合は、とにかくビューを再作成するため、マニフェストに_Android:configChanges="orientation"
_を入れません。
次の方法を使用して、アクティビティの現在の状態(入力されたテキスト、表示されたダイアログ、表示されたデータなど)を保存します。
_@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
}
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
}
_
そのようにして、アクティビティは再びonCreateを通過し、その後、onRestoreInstanceStateメソッドを呼び出します。このメソッドでは、EditText値を再度設定できます。
より複雑なオブジェクトを保存する場合は、使用できます
_@Override
public Object onRetainNonConfigurationInstance() {
}
_
ここでは、任意のオブジェクトを保存でき、onCreateでgetLastNonConfigurationInstance();
を呼び出すだけでオブジェクトを取得できます。
「すべてを正しく行う」ことやDialogFragment
などを使用する場合でも、これはまだ問題のようです。
Google Issue Tracker にはスレッドがあります。これは、メッセージキューに残っている古い破棄メッセージが原因であると主張しています。提供される回避策は非常に簡単です。
@Override
public void onDestroyView() {
/* Bugfix: https://issuetracker.google.com/issues/36929400 */
if (getDialog() != null && getRetainInstance())
getDialog().setDismissMessage(null);
super.onDestroyView();
}
この問題が最初に報告されてから7年が経過しても、これが必要であることは信じられません。
DialogのonSave/onRestoreメソッドをActivityのonSave/onRestoreメソッドと組み合わせて、Dialogの状態を保持できます。
注:このメソッドは、アラートメッセージの表示など、これらの「単純な」ダイアログに対して機能します。ダイアログに埋め込まれたWebViewのコンテンツは再現しません。複雑なダイアログが回転中に消えないようにしたい場合は、Chung IWの方法を試してください。
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
myDialog.onRestoreInstanceState(savedInstanceState.getBundle("DIALOG"));
// Put your codes to retrieve the EditText contents and
// assign them to the EditText here.
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
// Put your codes to save the EditText contents and put them
// to the outState Bundle here.
outState.putBundle("DIALOG", myDialog.onSaveInstanceState());
}
間違いなく、最良のアプローチはDialogFragmentを使用することです。
ラッパークラスの私のソリューションは、1つのFragment(または小さなリファクタリングを伴うActivity)内で異なるダイアログが消えないようにするのに役立ちます。また、何らかの理由で、アクション、外観、またはその他の点でコード間にわずかな違いがあるAlertDialogs
が散在している場合、大規模なコードのリファクタリングを回避するのに役立ちます。
_public class DialogWrapper extends DialogFragment {
private static final String ARG_DIALOG_ID = "ARG_DIALOG_ID";
private int mDialogId;
/**
* Display dialog fragment.
* @param invoker The fragment which will serve as {@link AlertDialog} alert dialog provider
* @param dialogId The ID of dialog that should be shown
*/
public static <T extends Fragment & DialogProvider> void show(T invoker, int dialogId) {
Bundle args = new Bundle();
args.putInt(ARG_DIALOG_ID, dialogId);
DialogWrapper dialogWrapper = new DialogWrapper();
dialogWrapper.setArguments(args);
dialogWrapper.setTargetFragment(invoker, 0);
dialogWrapper.show(invoker.getActivity().getSupportFragmentManager(), null);
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mDialogId = getArguments().getInt(ARG_DIALOG_ID);
}
@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
return getDialogProvider().getDialog(mDialogId);
}
private DialogProvider getDialogProvider() {
return (DialogProvider) getTargetFragment();
}
public interface DialogProvider {
Dialog getDialog(int dialogId);
}
}
_
Activityに関しては、getContext()
内でonCreateDialog()
を呼び出し、DialogProvider
インターフェイスにキャストして、mDialogId
によって特定のダイアログを要求できます。ターゲットフラグメントを処理するためのすべてのロジックを削除する必要があります。
フラグメントからの使用:
_public class MainFragment extends Fragment implements DialogWrapper.DialogProvider {
private static final int ID_CONFIRMATION_DIALOG = 0;
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
Button btnHello = (Button) view.findViewById(R.id.btnConfirm);
btnHello.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
DialogWrapper.show(MainFragment.this, ID_CONFIRMATION_DIALOG);
}
});
}
@Override
public Dialog getDialog(int dialogId) {
switch (dialogId) {
case ID_CONFIRMATION_DIALOG:
return createConfirmationDialog(); //Your AlertDialog
default:
throw new IllegalArgumentException("Unknown dialog id: " + dialogId);
}
}
}
_
あなたは私のブログで完全な記事を読むことができます Dialogが消えないようにするには? そして source code で遊んでください。
非常に簡単なアプローチは、メソッドonCreateDialog()
からダイアログを作成することです(以下の注を参照)。 showDialog()
で表示します。この方法では、Androidは回転を処理します。WindowLeakを回避するためにdismiss()
でonPause()
を呼び出す必要はありません。ダイアログを復元します。ドキュメントから:
このアクティビティが管理するダイアログを表示します。 onCreateDialog(int、Bundle)の呼び出しは、指定されたIDに対して最初に呼び出されたときに同じIDで行われます。その後、ダイアログは自動的に保存および復元されます。
詳細については、 Android docs showDialog() を参照してください。それが誰かを助けることを願っています!
注:AlertDialog.Builderを使用する場合、show()
からonCreateDialog()
を呼び出さないで、create()
代わりに。 ProgressDialogを使用する場合は、オブジェクトを作成し、必要なパラメーターを設定して、それを返します。結論として、show()
内のonCreateDialog()
は問題を引き起こし、de Dialogインスタンスを作成してそれを返します。これは動作するはずです! (onCreate()からshowDialog()を使用して実際にダイアログを表示しない問題を経験しましたが、onResume()またはリスナーコールバックで使用するとうまく機能します)。
この質問はずっと前に回答されました。
まだこれはnon-hackyとsimpleのソリューションです。
私は このヘルパークラス を使用したので、アプリケーションでも使用できます。
使用法は次のとおりです。
PersistentDialogFragment.newInstance(
getBaseContext(),
RC_REQUEST_CODE,
R.string.message_text,
R.string.positive_btn_text,
R.string.negative_btn_text)
.show(getSupportFragmentManager(), PersistentDialogFragment.TAG);
または
PersistentDialogFragment.newInstance(
getBaseContext(),
RC_EXPLAIN_LOCATION,
"Dialog title",
"Dialog Message",
"Positive Button",
"Negative Button",
false)
.show(getSupportFragmentManager(), PersistentDialogFragment.TAG);
public class ExampleActivity extends Activity implements PersistentDialogListener{
@Override
void onDialogPositiveClicked(int requestCode) {
switch(requestCode) {
case RC_REQUEST_CODE:
break;
}
}
@Override
void onDialogNegativeClicked(int requestCode) {
switch(requestCode) {
case RC_REQUEST_CODE:
break;
}
}
}
同様の問題がありました。画面の向きが変わると、ユーザーがダイアログを閉じなかったにもかかわらず、ダイアログのonDismiss
リスナーが呼び出されました。代わりにonCancel
リスナーを使用してこの問題を回避することができました。これは、ユーザーが戻るボタンを押したときと、ユーザーがダイアログの外側をタッチしたときにトリガーしました。