简体   繁体   中英

onCreateView() for Fragment being called before Activity onRestoreInstanceState()

So I have a fragment that is attached to an activity and I'm trying to make sure things go smoothly when the screen is rotated (or anything that would interrupt the activity). In order to do this, I use the methods onSaveInstanceState and onRestoreInstanceState in my activity to keep the information that my activity stores.

When the view for my fragment is created, the fragment asks the Activity for information (This is in onCreateView() for the fragment):

ArrayList<String> picList = mListener.getPics();
ArrayList<String> descripList = mListener.getDescriptions();

In order for the fragment to create the view, it needs access to picList and descripList, which are member variables for the activity. These member variables are stored and restored in onSaveInstanceState and onRestoreInstanceState.

protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    if(photoFile != null)
        outState.putString("photoFile", photoFile.getAbsolutePath());
    outState.putString("currentFragTag", currentFragTag);
    outState.putStringArrayList("picList", picList);
    outState.putStringArrayList("descripList", descripList);
}

@Override
protected void onRestoreInstanceState(Bundle saved) {
    super.onRestoreInstanceState(saved);
    if(saved.getString("photoFile") != null)
        photoFile = new File(saved.getString("photoFile"));
    currentFragTag = saved.getString("currentFragTag");
    picList = saved.getStringArrayList("picList");
    descripList = saved.getStringArrayList("descripList");
    currentFrag = getFragmentManager().findFragmentByTag(currentFragTag);
    changeFrag(currentFrag, currentFragTag);
}

The problem is, onCreateView() is being called before onRestoreInstanceState() is being called in the activity. I tried using onActivityCreated() in the fragment instead, but that was also being called before onRestoreInstanceState(). With a debugger attached, when the screen is rotated, onRestoreInstanceState() is always called last. This means that the fragment does not have access to the activity's information when creating the view.

Is this supposed to happen? How can I have my fragment's view use information from the activity when the activity is being restored?

Updated response:

Read the alternatives Passing data between a fragment and its container activity . Also see this .

Previous response revised:

See this and try to place your code in onResume() and invalidate the view or detach/attach the fragment as a quick solution but is not the best solution as Alex Lockwood said:

Fragments are re-usable UI components. They have their own lifecycle, display their own view, and define their own behavior. You usually don't need to have your Activity mess around with the internal workings of a Fragment, as the Fragment's behavior should be self-contained and independent of any particular Activity.

If you really need the code before, override the next methods and directly save/restore the required data in the fragment:

/**
 * Called when the fragment's activity has been created and this
 * fragment's view hierarchy instantiated.  It can be used to do final
 * initialization once these pieces are in place, such as retrieving
 * views or restoring state.  It is also useful for fragments that use
 * {@link #setRetainInstance(boolean)} to retain their instance,
 * as this callback tells the fragment when it is fully associated with
 * the new activity instance.  This is called after {@link #onCreateView}
 * and before {@link #onViewStateRestored(Bundle)}.
 *
 * @param savedInstanceState If the fragment is being re-created from
 * a previous saved state, this is the state.
 */
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);
    if (savedInstanceState != null) {
        restoreInstanceState(savedInstanceState);
    }
}

/**
 * Called to ask the fragment to save its current dynamic state, so it
 * can later be reconstructed in a new instance of its process is
 * restarted.  If a new instance of the fragment later needs to be
 * created, the data you place in the Bundle here will be available
 * in the Bundle given to {@link #onCreate(Bundle)},
 * {@link #onCreateView(LayoutInflater, ViewGroup, Bundle)}, and
 * {@link #onActivityCreated(Bundle)}.
 *
 * <p>This corresponds to {@link Activity#onSaveInstanceState(Bundle)
 * Activity.onSaveInstanceState(Bundle)} and most of the discussion there
 * applies here as well.  Note however: <em>this method may be called
 * at any time before {@link #onDestroy()}</em>.  There are many situations
 * where a fragment may be mostly torn down (such as when placed on the
 * back stack with no UI showing), but its state will not be saved until
 * its owning activity actually needs to save its state.
 *
 * @param outState Bundle in which to place your saved state.
 */
@Override
public void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    outState.put...;
}

And create this one, used to retrieve the needed data from bundle:

public void restoreInstanceState(Bundle savedInstanceState) {
    ... = savedInstanceState.get...
}

or use getActivity() method to directly access to some method or field from here if you need the code on your activity for some reason.

/**
 * Return the {@link FragmentActivity} this fragment is currently associated with.
 * May return {@code null} if the fragment is associated with a {@link Context}
 * instead.
 */
final public FragmentActivity getActivity() {
    return mHost == null ? null : (FragmentActivity) mHost.getActivity();
}

For example: ((YourActivity) getActivity()).getPics();

And add the getPics() method to the activity.

Further information here and an alternative solution defining an interface here .

I think the most easiest way is using EventBus.
You can send a "msg" when your activity is recreated, and your fragment's "target method" will get this msg(the msg is Object, it can be a bundle).

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