Implementasi berikut dapat digunakan untuk memecahkan masalah melakukan perubahan status dengan aman selama Activity
siklus hidup, khususnya untuk menampilkan dialog: jika status instans telah disimpan (misalnya karena perubahan konfigurasi), ia akan menundanya hingga status dilanjutkan telah dilakukan.
public abstract class XAppCompatActivity extends AppCompatActivity {
private String TAG = this.getClass().getSimpleName();
/** The retained fragment for this activity */
private ActivityRetainFragment retainFragment;
/** If true the instance state has been saved and we are going to die... */
private boolean instanceStateSaved;
@Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
// get hold of retain Fragment we'll be using
retainFragment = ActivityRetainFragment.get(this, "Fragment-" + this.getClass().getName());
}
@Override
protected void onPostResume() {
super.onPostResume();
// reset instance saved state
instanceStateSaved = false;
// execute all the posted tasks
for (ActivityTask task : retainFragment.tasks) task.exec(this);
retainFragment.tasks.clear();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
instanceStateSaved = true;
}
/**
* Checks if the activity state has been already saved.
* After that event we are no longer allowed to commit fragment transactions.
* @return true if the instance state has been saved
*/
public boolean isInstanceStateSaved() {
return instanceStateSaved;
}
/**
* Posts a task to be executed when the activity state has not yet been saved
* @param task The task to be executed
* @return true if the task executed immediately, false if it has been queued
*/
public final boolean post(ActivityTask task)
{
// execute it immediately if we have not been saved
if (!isInstanceStateSaved()) {
task.exec(this);
return true;
}
// save it for better times
retainFragment.tasks.add(task);
return false;
}
/** Fragment used to retain activity data among re-instantiations */
public static class ActivityRetainFragment extends Fragment {
/**
* Returns the single instance of this fragment, creating it if necessary
* @param activity The Activity performing the request
* @param name The name to be given to the Fragment
* @return The Fragment
*/
public static ActivityRetainFragment get(XAppCompatActivity activity, String name) {
// find the retained fragment on activity restarts
FragmentManager fm = activity.getSupportFragmentManager();
ActivityRetainFragment fragment = (ActivityRetainFragment) fm.findFragmentByTag(name);
// create the fragment and data the first time
if (fragment == null) {
// add the fragment
fragment = new ActivityRetainFragment();
fm.beginTransaction().add(fragment, name).commit();
}
return fragment;
}
/** The queued tasks */
private LinkedList<ActivityTask> tasks = new LinkedList<>();
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
// retain this fragment
setRetainInstance(true);
}
}
/** A task which needs to be performed by the activity when it is "fully operational" */
public interface ActivityTask {
/**
* Executed this task on the specified activity
* @param activity The activity
*/
void exec(XAppCompatActivity activity);
}
}
Kemudian gunakan kelas seperti ini:
/** AppCompatDialogFragment implementing additional compatibility checks */
public abstract class XAppCompatDialogFragment extends AppCompatDialogFragment {
/**
* Shows this dialog as soon as possible
* @param activity The activity to which this dialog belongs to
* @param tag The dialog fragment tag
* @return true if the dialog has been shown immediately, false if the activity state has been saved
* and it is not possible to show it immediately
*/
public boolean showRequest(XAppCompatActivity activity, final String tag) {
return showRequest(activity, tag, null);
}
/**
* Shows this dialog as soon as possible
* @param activity The activity to which this dialog belongs to
* @param tag The dialog fragment tag
* @param args The dialog arguments
* @return true if the dialog has been shown immediately, false if the activity state has been saved
* and it is not possible to show it immediately
*/
public boolean showRequest(XAppCompatActivity activity, final String tag, final Bundle args)
{
return activity.post(new XAppCompatActivity.ActivityTask() {
@Override
public void exec(XAppCompatActivity activity) {
if (args!= null) setArguments(args);
show(activity.getSupportFragmentManager(), tag);
}
});
}
/**
* Dismiss this dialog as soon as possible
* @return true if the dialog has been dismissed immediately, false if the activity state has been saved
* and it is not possible to dismissed it immediately
*/
public boolean dismissRequest()
{
return dismissRequest(null);
}
/**
* Dismiss this dialog as soon as possible
* @param runnable Actions to be performed before dialog dismissal
* @return true if the dialog has been dismissed immediately, false if the activity state has been saved
* and it is not possible to dismissed it immediately
*/
public boolean dismissRequest(final Runnable runnable)
{
// workaround as in rare cases the activity could be null
XAppCompatActivity activity = (XAppCompatActivity)getActivity();
if (activity == null) return false;
// post the dialog dismissal
return activity.post(new XAppCompatActivity.ActivityTask() {
@Override
public void exec(XAppCompatActivity activity) {
if (runnable != null) runnable.run();
dismiss();
}
});
}
}
Anda dapat dengan aman menampilkan dialog tanpa mengkhawatirkan status aplikasi:
public class TestDialog extends XAppCompatDialogFragment {
private final static String TEST_DIALOG = "TEST_DIALOG";
public static void show(XAppCompatActivity activity) {
new TestDialog().showRequest(activity, TEST_DIALOG);
}
public TestDialog() {}
@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState)
{
return new AlertDialog.Builder(getActivity(), R.style.DialogFragmentTheme /* or null as you prefer */)
.setTitle(R.string.title)
// set all the other parameters you need, e.g. Message, Icon, etc.
).create();
}
}
dan kemudian panggil TestDialog.show(this)
dari dalam Anda XAppCompatActivity
.
Jika Anda ingin membuat kelas dialog yang lebih umum dengan parameter, Anda dapat menyimpannya di a Bundle
dengan argumen di show()
metode dan mengambilnya dengan getArguments()
in onCreateDialog()
.
Keseluruhan pendekatan mungkin tampak sedikit rumit, tetapi setelah Anda membuat dua kelas dasar untuk aktivitas dan dialog, ini cukup mudah digunakan dan bekerja dengan sempurna. Ini dapat digunakan untuk Fragment
operasi berbasis lain yang dapat dipengaruhi oleh masalah yang sama.