I want to display a loading dialog when the user navigates back to my activity
prior to resuming the activity
- is this possible?
Here's some background - when the activity is first launched a loading dialog
is displayed while some cached state is loaded from a file. This takes under a second on newer phones but may take longer on older models, too long to run on the UI thread in any event. The cached state may be destroyed by the garbage collector (or the process may be killed) before the user navigates back to the activity, which leads to problems resuming the activity. Specifically, restored fragment life-cycle events begin to fire inside the activity's onCreate
method and they depend heavily on the cached state. Ideally, a loading dialog should be displayed and the life-cycle events of child fragments
should be delayed until after the cached state is restored.
Alternatively I could check whether or not these resources are available prior to initializing every fragment/activity, however if that approach were used then restoring the fragment's state would likely need to be delayed until after onResume
- I would expect that to lead to problems properly restoring any saved instance state used by the fragment's parent classes. Does the framework provide capabilities to facilitate this?
UPDATE
A (contrived) example is provided below - the activity displays a loading dialog following which a button is displayed to create a dialog fragment. At this point the activity is terminated and re-launched; as expected the test dialog is automatically restored before the loading dialog completes. The question is how can (or can ) this process be delayed so that the loading dialog completes before the test dialog is restored.
The activity class:
public class MainActivity extends AppCompatActivity {
private static final String TAG = MainActivity.class.getSimpleName();
private ProgressDialog dialog_ = null;
private Button button_ = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
Log.v(TAG, "onCreate: start");
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button_ = (Button)findViewById(R.id.testButton);
// A loading dialog is displayed when the activity is created if the cached state is null
if (State.get() == null) {
// Using a button here instead of some content fragment for convenience
button_.setVisibility(View.GONE);
// Create a loading dialog
dialog_ = new ProgressDialog(this);
dialog_.setMessage("Loading...");
dialog_.setIndeterminate(true);
dialog_.show();
// Create the cached state in a background thread
new Thread(new Runnable() {
@Override
public void run() {
Log.v(TAG, "State.create: start");
State.create(MainActivity.this);
Log.v(TAG, "State.create: end");
runOnUiThread(new Runnable() {
@Override
public void run() {
if (dialog_ != null) {
dialog_.dismiss();
dialog_ = null;
}
// When the loading dialog is finished the content fragment is loaded;
// here the button is merely displayed. Ideally the life-cycle events
// in TestDialog should not be called until after this point.
button_.setVisibility(View.VISIBLE);
Log.v(TAG, "Loading finished");
}
});
}
}).start();
}
Log.v(TAG, "onCreate: end");
}
public void handleTestButton (final View view) {
Log.v(TAG, "handleTestButton");
// A dialog fragment is added here; the framework will automatically restore the fragment
// if the activity is terminated and restored.
new TestDialog().show(getSupportFragmentManager(), null);
}
}
The test dialog:
public class TestDialog extends DialogFragment {
private static final String TAG = TestDialog.class.getSimpleName();
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
if (State.get() == null)
Log.w(TAG, "onAttach: state was null");
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (State.get() == null)
Log.w(TAG, "onCreate: state was null");
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
if (State.get() == null)
Log.w(TAG, "onCreateView: state was null");
return inflater.inflate(R.layout.test_dialog, container, false);
}
}
The shared state:
public class State {
private static Object state_ = null;
// A long running process is performed on a background thread; locking omitted for clarity
public static void create (final Context context) {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
}
state_ = new Object();
}
// Fragment life-cycle events require the cached state
public static Object get () {
return state_;
}
}
When the above is run the following is initially produced:
onCreate: start
onCreate: end
State.create: start
State.create: end
Loading finished
handleTestButton
After terminating and re-launching the app the following is produced:
onCreate: start
onAttach: state was null
onCreate: state was null
onCreate: end
State.create: start
onCreateView: state was null
State.create: end
Loading finished
You can move the logic of attaching the fragments to your activity's onResume()
method from your onCreate()
method, because it is also called at the time of starting an activity for first time.
Now that your logic is in onResume()
, you can show a ProgressDialod
as soon as as onResume
gets called. Then you have to check when your cached data has finished loading. When it loads completely, then you can dismiss the ProgressDialog
and write the logic for attaching the fragments.
I assume that you can get some callbacks when the loading is finished, if it is not the case, you might need to chain these events.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.