Pertanyaan Mencegah pemecatan dialog pada rotasi layar di Android


Saya mencoba mencegah dialog yang dibuat dengan pembuat Alert tidak diberhentikan ketika Aktivitas dimulai ulang.

Jika saya membebani metode onConfigurationChanged, saya berhasil melakukan ini dan mengatur ulang tata letak untuk memperbaiki orientasi, tetapi saya kehilangan fitur teks lengket dari teks. Jadi dalam memecahkan masalah dialog, saya telah membuat masalah edittext ini.

Jika saya menyimpan string dari edittext dan menetapkan kembali mereka dalam perubahan onCofiguration mereka masih tampak default ke nilai awal bukan apa yang dimasukkan sebelum rotasi. Bahkan jika saya memaksa yang tidak valid tampaknya memperbarui mereka.

Saya benar-benar perlu memecahkan masalah dialog atau masalah edittext.

Terima kasih untuk bantuannya.


75
2017-09-26 15:14


asal


Jawaban:


Cara terbaik untuk menghindari masalah ini saat ini adalah dengan menggunakan DialogFragment.

Buat kelas baru yang diperluas DialogFragment. Mengesampingkan onCreateDialog dan kembalikan yang lama Dialog atau sebuah AlertDialog.

Maka Anda bisa menunjukkannya dengan DialogFragment.show(fragmentManager, tag).

Berikut ini contoh dengan 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();
    }
}

Dan dalam Kegiatan yang Anda panggil:

new MyDialogFragment().show(getSupportFragmentManager(), "tag"); // or getFragmentManager() in API 11+

Jawaban ini membantu menjelaskan ketiga pertanyaan lainnya (dan jawaban mereka):


115
2018-03-31 13:19



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

40
2017-12-05 07:51



Jika Anda mengubah tata letak pada perubahan orientasi saya tidak akan menempatkan android:configChanges="orientation" dalam manifes Anda karena Anda menciptakan kembali tampilan.

Simpan keadaan saat ini dari aktivitas Anda (seperti teks yang dimasukkan, dialog yang ditampilkan, data yang ditampilkan, dll.) Menggunakan metode ini:

@Override
protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
}

@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
    super.onRestoreInstanceState(savedInstanceState);
}

Dengan cara itu, aktivitas berjalan melalui onCreate lagi dan setelah itu memanggil metode onRestoreInstanceState di mana Anda dapat mengatur nilai EditText Anda lagi.

Jika Anda ingin menyimpan Objek yang lebih kompleks yang dapat Anda gunakan

@Override
public Object onRetainNonConfigurationInstance() {
}

Di sini Anda dapat menyimpan objek apa saja dan di onCreate Anda hanya perlu menelepon getLastNonConfigurationInstance(); untuk mendapatkan Objek.


5
2017-09-26 16:45



Cukup tambahkan android: configChanges = "orientation" dengan aktivitas Anda  elemen di AndroidManifest.xml

Contoh:

<activity
            android:name=".YourActivity"
            android:configChanges="orientation"
            android:label="@string/app_name"></activity>

2
2018-06-27 05:43



Pertanyaan ini sudah terjawab sejak lama.

Padahal ini non-hacky dan sederhana solusi yang saya gunakan untuk diri saya sendiri.

aku melakukannya kelas penolong ini untuk saya sendiri, sehingga Anda dapat menggunakannya dalam aplikasi Anda juga.

Penggunaannya adalah:

PersistentDialogFragment.newInstance(
        getBaseContext(),
        RC_REQUEST_CODE,
        R.string.message_text,
        R.string.positive_btn_text,
        R.string.negative_btn_text)
        .show(getSupportFragmentManager(), PersistentDialogFragment.TAG);

Atau

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

2
2018-06-23 13:00



Pendekatan yang sangat mudah adalah membuat dialog dari metode onCreateDialog() (lihat catatan di bawah). Anda menunjukkan kepada mereka melalui showDialog(). Dengan cara ini, Android menangani rotasi untuk Anda dan Anda tidak perlu menelepon dismiss() di onPause() untuk menghindari WindowLeak dan kemudian Anda tidak perlu mengembalikan dialog. Dari dokumen:

Tampilkan dialog yang dikelola oleh aktivitas ini. Panggilan ke onCreateDialog (int, Bundle) akan dibuat dengan id yang sama saat pertama kali dipanggil untuk id yang diberikan. Sejak saat itu, dialog akan secara otomatis disimpan dan dipulihkan.

Lihat Dokumen Android showDialog () untuk info lebih lanjut. Semoga ini membantu seseorang!

catatan:Jika menggunakan AlertDialog.Builder, jangan panggil show() dari onCreateDialog(), hubungi create() sebagai gantinya. Jika menggunakan ProgressDialog, cukup buat objek, atur parameter yang Anda perlukan dan kembalikan. Kesimpulannya, show() dalam onCreateDialog() menyebabkan masalah, cukup buat de Contoh dialog dan kembalikan. Ini harus bekerja! (Saya telah mengalami masalah menggunakan showDialog () dari onCreate () -tentu tidak menunjukkan dialog-, tetapi jika Anda menggunakannya di onResume () atau dalam callback pendengar, itu berfungsi dengan baik).


1
2018-02-05 22:29



Anda bisa menggabungkan Dialog onSave / onRestore metode dengan Aktifitas onSave / onRestore metode untuk menjaga keadaan Dialog.

catatan: Metode ini berfungsi untuk Dialog "sederhana", seperti menampilkan pesan peringatan. Itu tidak akan mereproduksi isi dari WebView yang tertanam dalam Dialog. Jika Anda benar-benar ingin mencegah dialog kompleks dari pemecatan selama rotasi, cobalah metode 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());
}

1
2018-02-03 23:57



Tentunya, pendekatan terbaik adalah dengan menggunakan DialogFragment.

Di sini adalah solusi tambang kelas pembungkus yang membantu mencegah berbagai dialog dikeluarkan dari satu Fragmen (atau Aktivitas dengan refactoring kecil). Juga, membantu untuk menghindari refactoring kode besar jika untuk beberapa alasan ada banyak AlertDialogs tersebar di antara kode dengan sedikit perbedaan di antara mereka dalam hal tindakan, penampilan atau sesuatu yang lain.

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

Saat terkait dengan Aktivitas, Anda dapat memohon getContext() dalam onCreateDialog(), berikan ke DialogProvider antarmuka dan minta dialog khusus oleh mDialogId. Semua logika untuk menangani fragmen target harus dihapus.

Penggunaan dari fragmen:

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

Anda dapat membaca artikel lengkap di blog saya Bagaimana cara mencegah Dialog diberhentikan? dan bermain dengan Kode sumber.


0
2018-01-13 16:49