简体   繁体   中英

Loading screen prior to resuming an activity

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM