【问题标题】:Execute operation from fragment after onRestoreInstanceState在 onRestoreInstanceState 之后从片段执行操作
【发布时间】:2017-02-18 11:09:45
【问题描述】:

我有一个执行某些网络操作的自定义视图。视图根据该操作结果构建 UI。

视图包含通过互联网获取的卡片列表。此视图在多个地方使用。假设其中一个是我的片段。

这是我在片段中所做的:

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);
    }
}

我的自定义视图如下所示:

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
    }
}

好的,现在当用户从我的应用切换到另一个应用时,我的 Fragment 可能会被破坏。我想保存我的自定义视图的状态。因此我的观点不需要再次从互联网上获取信息。所以我在CardHelper 后面加上以下数据(基于this 答案):

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];
                    }
                };
    }
}

为了争论,我想保存这个视图本身的视图数据。因此片段/活动或 w/e 使用它不需要知道它在内部是如何工作的。如果我在多个地方使用它,我就不需要复制存储\恢复此视图的代码。

好的,现在解决问题

第一次创建 CardHelper 时,我执行 init 以使用一些 data 手动初始化视图。当我的片段被破坏并且应用程序进入后台然后被恢复时,方法将按以下优先级执行:

  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) {

如您所见,onRestoreInstanceState 仅在 onActivityCreated 之后执行。但我需要知道在此之前我是否应该在init 方法中执行网络操作。所以我想先执行onRestoreInstanceState,然后再执行init。但是在片段LifeCycle 中没有可以在此之后完成的方法。

在调用CardHelper 上的onRestoreInstanceState 后,如何重新格式化我可以在片段中调用某些操作的代码?还有一件事是onRestoreInstanceState 在创建CardHelper 时第一次不会被调用。但在这种情况下,我也需要初始化 CardHelper。

【问题讨论】:

    标签: android android-fragments android-savedstate


    【解决方案1】:

    简单的解决方法应该是在布置cardHelper 之后发布init() 步骤,因此onRestoreInstanceState 已经被调用。为此,您只需在post(...) 中执行init()

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

    还没有测试过,我认为它会工作。

    【讨论】:

    • 是的,这行得通。可能有一个更优雅的解决方案。
    • 代码中的问题是,View 知道业务逻辑。通常,它不应该这样发生。优雅的解决方案不是将数据保存在视图本身中,而是考虑更改您的架构。
    • 您能否建议应该如何完成?这个想法是封装逻辑以查看自身。因此,使用我的视图的人无需担心任何超出 layout.xml 的视图。如果我将逻辑从我的视图中移开,用户应该知道他必须手动保存包。
    • 如果您有这样的用例,更好的解决方案是自己在您的视图中执行post(),而不是依赖客户代表他执行它。客户端将调用正常的init,您将在您的视图中调用post 初始化逻辑。
    • 不过,您在 Nougat 中可能会遇到问题,这会限制在 Bundle 中保存数据。尝试在 bundle 中保存太多数据时会出现异常。
    猜你喜欢
    • 1970-01-01
    • 2011-07-21
    • 2014-09-04
    • 1970-01-01
    • 2016-07-22
    • 1970-01-01
    • 2013-07-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多