Android에서 화면 회전시 대화 상자 닫기 방지
활동이 다시 시작될 때 경고 빌더로 빌드 된 대화 상자가 닫히지 않도록 방지하려고합니다.
onConfigurationChanged 메서드를 오버로드하면 성공적으로이 작업을 수행하고 레이아웃을 올바른 방향으로 재설정 할 수 있지만 edittext의 고정 텍스트 기능이 손실됩니다. 그래서 대화 문제를 해결하면서이 edittext 문제를 만들었습니다.
편집 텍스트에서 문자열을 저장하고 onCofiguration 변경에서 다시 할당하면 여전히 회전 전에 입력 한 값이 아닌 초기 값으로 기본 설정되는 것처럼 보입니다. 강제로 무효화하더라도 업데이트하는 것 같습니다.
대화 문제 나 edittext 문제를 해결해야합니다.
도와 주셔서 감사합니다.
요즘이 문제를 피하는 가장 좋은 방법은 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+
이 답변은 다음 세 가지 질문 (및 답변)을 설명하는 데 도움이됩니다.
- Android 기기 회전 후 대화 상자를 닫는 가장 좋은 방법
- Android DialogFragment 대 Dialog
- 호환성 패키지를 사용하여 DialogFragment를 어떻게 표시 할 수 있습니까?
// 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);
}
방향 변경시 레이아웃을 변경하는 경우 android:configChanges="orientation"
어쨌든 뷰를 다시 생성하기 때문에 매니페스트에 넣지 않을 것 입니다.
다음 방법을 사용하여 활동의 현재 상태 (예 : 입력 한 텍스트, 표시된 대화 상자, 표시된 데이터 등)를 저장합니다.
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
}
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
}
이렇게하면 활동이 다시 onCreate를 거치고 나중에 EditText 값을 다시 설정할 수있는 onRestoreInstanceState 메서드를 호출합니다.
더 복잡한 객체를 저장하려면 다음을 사용할 수 있습니다.
@Override
public Object onRetainNonConfigurationInstance() {
}
여기에 모든 객체를 저장할 수 있으며 onCreate에서 객체 getLastNonConfigurationInstance();
를 가져 오기 위해 호출 하기 만하면 됩니다.
AndroidManifest.xml의 활동 요소와 함께 android : configChanges = "orientation"을 추가하기 만하면됩니다.
예:
<activity
android:name=".YourActivity"
android:configChanges="orientation"
android:label="@string/app_name"></activity>
매우 쉬운 방법은 메서드에서 대화 상자를 만드는 것입니다 onCreateDialog()
(아래 참고 참조). 을 통해 보여줍니다 showDialog()
. 이 방법은, 안드로이드는 당신을위한 회전을 처리하고 당신이 호출 할 필요가 없습니다 dismiss()
에 onPause()
WindowLeak를 방지하고 다음 대화 상자를 복원 할 수없는 둘 수 있습니다. 문서에서 :
이 활동에서 관리하는 대화 상자를 표시합니다. onCreateDialog (int, Bundle)에 대한 호출은 주어진 ID에 대해 처음 호출 될 때 동일한 ID로 이루어집니다. 이후부터 대화 상자가 자동으로 저장되고 복원됩니다.
자세한 내용은 Android 문서 showDialog () 를 참조하세요. 누군가에게 도움이되기를 바랍니다!
참고 : AlertDialog.Builder를 사용하는 경우 show()
에서 onCreateDialog()
호출 create()
하지 말고 대신 호출하십시오 . ProgressDialog를 사용하는 경우 개체를 만들고 필요한 매개 변수를 설정 한 다음 반환하면됩니다. 결론적으로 show()
내부에서 onCreateDialog()
문제 가 발생하면 Dialog 인스턴스를 생성하고 반환하면됩니다. 작동합니다! (onCreate ()에서 showDialog ()를 사용하여 문제가 발생했습니다-실제로 대화 상자를 표시하지 않지만 onResume () 또는 리스너 콜백에서 사용하면 잘 작동합니다).
This question was answered a long time ago.
Yet this is non-hacky and simple solution I use for myself.
I did this helper class for myself, so you can use it in your application too.
Usage is:
PersistentDialogFragment.newInstance(
getBaseContext(),
RC_REQUEST_CODE,
R.string.message_text,
R.string.positive_btn_text,
R.string.negative_btn_text)
.show(getSupportFragmentManager(), PersistentDialogFragment.TAG);
Or
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;
}
}
}
You can combine the Dialog's onSave/onRestore methods with the Activity's onSave/onRestore methods to keep the state of the Dialog.
Note: This method works for those "simple" Dialogs, such as displaying an alert message. It won't reproduce the contents of a WebView embedded in a Dialog. If you really want to prevent a complex dialog from dismissal during rotation, try Chung IW's method.
@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());
}
Definitely, the best approach is by using DialogFragment.
Here is mine solution of wrapper class that helps to prevent different dialogs from being dismissed within one Fragment (or Activity with small refactoring). Also, it helps to avoid massive code refactoring if for some reasons there are a lot of AlertDialogs
scattered among the code with slight differences between them in terms of actions, appearance or something else.
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);
}
}
When it comes to Activity you can invoke getContext()
inside onCreateDialog()
, cast it to the DialogProvider
interface and request a specific dialog by mDialogId
. All logic to dealing with a target fragment should be deleted.
Usage from fragment:
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);
}
}
}
You can read the complete article on my blog How to prevent Dialog being dismissed? and play with the source code.
It seems that this is still an issue, even when "doing everything right" and using DialogFragment
etc.
There is a thread on Google Issue Tracker which claims that it is due to an old dismiss message being left in the message queue. The provided workaround is quite simple:
@Override
public void onDestroyView() {
/* Bugfix: https://issuetracker.google.com/issues/36929400 */
if (getDialog() != null && getRetainInstance())
getDialog().setDismissMessage(null);
super.onDestroyView();
}
Incredible that this is still needed 7 years after that issue was first reported.
I had a similar problem: when the screen orientation changed, the dialog's onDismiss
listener was called even though the user didn't dismiss the dialog. I was able to work around this by instead using the onCancel
listener, which triggered both when the user pressed the back button and when the user touched outside of the dialog.
Just use
ConfigurationChanges = Android.Content.PM.ConfigChanges.Orientation | Android.Content.PM.ConfigChanges.ScreenSize
and app will know how to handle rotation and screen size.
참고URL : https://stackoverflow.com/questions/7557265/prevent-dialog-dismissal-on-screen-rotation-in-android
'developer tip' 카테고리의 다른 글
JSON에서 각 이름이 인용되는 이유는 무엇입니까? (0) | 2020.09.05 |
---|---|
체스 판에서 기사의 최단 경로 (0) | 2020.09.05 |
namedtuple에 힌트 입력 (0) | 2020.09.05 |
Xcode 8 및 iOS10부터 viewDidLayoutSubviews에서보기 크기가 적절하지 않습니다. (0) | 2020.09.05 |
describeContents ()가 언제 어디서 사용됩니까? (0) | 2020.09.05 |