简体   繁体   中英

Execute operation from fragment after onRestoreInstanceState

I have a custom view that performs some network operations. From that operation result the view builds UI.

The view contains a list of cards that are fetched via internet. This view is used in multiple places. Lets say one of them is my fragment.

Here's what I do inside of fragment:

class MyFragment extends Fragment  {
    // same as findViewById
    @BindView(R.id.card_list) CardHelper cardHelper;

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        // init my element with some data before it initializes
        cardHelper.init(data);
    }
}

Here's how my custom view looks like:

public class CardHelper extends ListView { 

   // some info that is built from internet data
   private List<HashMap<String, String>> cardElements = new ArrayList<>();

    public void init(Data data) {
        // does async network and then build a view based on results
        // Network operations could depend on data param
    }
}

OK, now when user switches from my app to another one, my Fragment could be destroyed. And I wanna saved the state of my custom view. Thus my view doesn't need to get information from internet again. So I append my CardHelper with the following data (based on this answer):

public class CardHelper extends ListView { 
   // some info that is built from internet data
   private List<HashMap<String, String>> cardElements = new ArrayList<>();

    public void init(Data data) {
        // does async network and then build a view based on results
    }

    @Override
    public Parcelable onSaveInstanceState() {
        Parcelable superState = super.onSaveInstanceState();
        SavedState ss = new SavedState(superState);
        ss.cardElements = this.cardElements;
        return ss;
    }

    @Override
    public void onRestoreInstanceState(Parcelable state) {
        if(state instanceof SavedState) {
            SavedState ss = (SavedState)state;
            super.onRestoreInstanceState(ss.getSuperState());
            this.cardElements = ss.cardElements;
        } else {
            super.onRestoreInstanceState(state);
        }
    }

    private static class SavedState extends BaseSavedState {
        private List<HashMap<String, String>> cardElements = new ArrayList<>();

        SavedState(Parcelable superState) {
            super(superState);
        }

        private SavedState(Parcel in) {
            super(in);
            this.cardElements = new ArrayList<>();
            in.readList(this.cardElements, null);
        }

        @Override
        public void writeToParcel(Parcel out, int flags) {
            super.writeToParcel(out, flags);
            out.writeList(this.cardElements);
        }

        public static final Parcelable.Creator<SavedState> CREATOR =
                new Parcelable.Creator<SavedState>() {
                    public SavedState createFromParcel(Parcel in) {
                        return new SavedState(in);
                    }

                    public SavedState[] newArray(int size) {
                        return new SavedState[size];
                    }
                };
    }
}

For the sake of argument, I wanna save the view's data from this view itself. So fragments/activities or w/e use it wouldn't need to know anything how it works inside. And if I use it from multiple places I wouldn't need to duplicate code that stores\\restores this view.

Ok, to the problem now :

When CardHelper is created the very first time I perform init to initialize the view manually with some data . When my fragment gets destroyed and app goes to background and then gets restored, methods are executed in the following priority:

  1. SavedState: private SavedState(Parcel in) {
  2. SavedState: public void writeToParcel(Parcel out, int flags) {
  3. CardHelper: public void init(Data data) {
  4. CardHelper: public void onRestoreInstanceState(Parcelable state) {

As you see onRestoreInstanceState executed only after onActivityCreated . But I need to know if I should perform network operation in init method before that. So I want to onRestoreInstanceState be executed first and only then init . But there're no method in fragments LifeCycle that could be done after this.

How to I reformat my code that I can call some operation within my fragment after onRestoreInstanceState on CardHelper gets called? One more thing that onRestoreInstanceState wouldn't be called for the first time when CardHelper is created. But I need to initialize my CardHelper in this case as well.

The easy fix should be posting the init() step after cardHelper has been laid out, therefore onRestoreInstanceState has already been called. To do that you just have to perform init() in post(...) :

cardHelper.post(new Runnable() {
                   public void run() {
                       cardHelper.init();
                   }
               });

Haven't tested it, I assume it will work.

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