MvpViewStateFragment not restoring ViewState on screen orientation

喜欢而已 提交于 2019-12-24 08:21:03

问题


I'm working on an Android app using Mosby MVP library. In one specific Fragment, the ViewState was implemented but not used (the state wasn't changed or anything). Some of the view logic is implemented by widgetManager. I made the state change correctly but the behavior is weird : on screen orientation, createViewState() and onNewViewStateInstance() are called after the viewState apply() : which cancels restoring the viewstate and related behaviors.

Do you have any idea why this is happening ?

I've implemented the ViewState as a RestorableParcelableViewState but the same thing happens.

After debugging : the cycle goes : onSaveInstanceState (fragment), saveInstanceState (viewstate), onViewCreated (f), apply (vs), [correct behavior but then], createViewState (f), onCreate (f), createPresenter (f), onViewCreated (f) and there everything is null again and restarts as if the fragment just got created with a null savedInstanceState.

Here is the core of the fragment :

public class DashboardFragment extends AuthViewStateFragment<DashboardView,
        DashboardPresenter> implements WidgetHolderView, FragmentSupportBack, DashboardView {

  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setRetainInstance(true);
  }

  @Override
  protected void injectDependencies() { // called in onViewCreated
    super.injectDependencies();
    presenter = new DashboardPresenter(dataService, getContext());
  }

  @Override
  public ViewState createViewState() {
    return new DashboardViewState();
  }

  @Override
  public void onNewViewStateInstance() {
    widgetManager.bindToWidgetHolderView(this, dashboardType, dashboardId);
    presenter.onNewInstance();
  }

  @Override
  public DashboardPresenter createPresenter() {
    return presenter;
  }

  @Override
  public void onViewCreated(View view, Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    recyclerView.setLayoutManager(layoutManager);
    recyclerView.setAdapter(adapter);
  }

  @Override
  public void showLoading() {
    ((DashboardViewState) viewState).showSpinnerLoading();
    loadingView.setVisibility(View.VISIBLE);
  }

  @Override
  public void showContent() {
    ((DashboardViewState) viewState).showSpinner();
    adapter.notifyDataSetChanged();
    loadingView.setVisibility(View.GONE);
  }

  @Override
  public void showError(String error) {
    ((DashboardViewState) viewState).showSpinnerError(new Throwable(error));
    errorView.setVisibility(View.VISIBLE);
    loadingView.setVisibility(View.GONE);
  }

  @Override
  public void scrollList(List<Widget> widgets) {
    ((DashboardViewState) viewState).showSpinner();
    ((DashboardViewState) viewState).setData(widgets, widgetManager.getFeeder());
    // scroll to widget
  }

  @Override
  public void onStart() {
    super.onStart();
    adapter.resubscribeWidgetToFeeder();
  }

  @Override
  public void onStop() {
    adapter.unsubscribeWidgetFromFeeder();
    super.onStop();
  }

  @Override
  public void onDestroyView() {
    adapter.flushReferencesToWidgetViews();
    super.onDestroyView();
  }

  @Override
  public void showSpinnerError(Throwable error) {
    ((DashboardViewState) viewState).showSpinnerError(new Throwable(error));
    // show error
  }

  @Override
  public void showSpinnerLoading() {
    ((DashboardViewState) viewState).showSpinnerLoading();
    // Display loading icon for the spinner
  }

  @Override
  public void setDashboardList(List<Dashboard> dashboardList) {
    // Set DashboardList
    this.dashboardList = dashboardList;
    ((MainActivity)getActivity()).setDashboardList(dashboardList);
  }

  @Override
  public void showSpinner() {
    ((DashboardViewState) viewState).showSpinner();
    // show spinner
    spinner.setOnItemSelectedListener(selectedListener);
    setSelectedDatacenter(DatacenetrUtils.datacenterId);
  }

  @Override
  public void setData(List<Widget> widgets, Feeder feeder) {
    widgetManager.setWidgets(widgets);
    widgetManager.setFeeder(feeder);
    adapter.setFeeder(widgetManager.getFeeder());
    adapter.notifyDataSetChanged();
  }
}

The viewstate :

class DashboardViewState implements ViewState<DashboardView> {
    private int state = LOADING;
    private Throwable t;
    private List<Widget> widgets;
    private Feeder feeder;

    @Override
    public void apply(DashboardView view, boolean retained) {
        switch (state) {
            case LOADING:
                view.showSpinnerLoading();
                break;
            case CONTENT:
                view.showSpinner();
                view.setData(widgets, feeder);
                break;
            case ERROR:
                view.showSpinnerError(t);
                break;
        }
    }

    public void showSpinnerLoading() {
        state = LOADING;
    }

    public void showSpinner() {
        state = CONTENT;
    }

    public void setData(List<Widget> widgets, Feeder feeder) {
        setWidgets(widgets);
        setFeeder(feeder);
    }

    public void setWidgets(List<Widget> widgets) {
        this.widgets = widgets;
    }

    public void setFeeder(Feeder feeder) {
        this.feeder = feeder;
    }

    public void showSpinnerError(Throwable t) {
        this.t = t;
        state = ERROR;
    }
}

The presenter:

public class DashboardPresenter
        extends Mvp2RxPresenter<DashboardView, List<Dashboard>> {
    private final DataService dataService;
    private final Context context;

    public DashboardPresenter(DataService dataService, Context context) {
        this.dataService = dataService;
        this.context = context;
    }

    public void onNewInstance() {
        if (isViewAttached())
            getView().showSpinnerLoading();
        if (isViewAttached()) getView().showSpinnerLoading();
        subscribe(dataService.getDatacenters()
                        .concatMap(Observable::from)
                        .map(this::datacenterToDashboard)
                        .startWith(dataService.getCurrentUser()
                                .map(user -> {
                                    Dashboard dashboard = new Dashboard (context.getString(R.string.dashboard_personalDashboard));
                                    return dashboard;
                                }))
                        .toList()
                , 0);
    }


    @Override
    protected void onNext(List<Dashboard> data, int pr) {
        if (isViewAttached()) {
            getView().setDashboardList(data);
        }
    }

    @Override
    protected void onError(Throwable e, int pr) {
        if (isViewAttached()) getView().showSpinnerError(e);
    }

    @Override
    protected void onCompleted(int pr) {
        if (isViewAttached()) getView().showSpinner();
    }
}

回答1:


I think you are accidentally adding a new DashboardFragment on each orientation change in your Activity, don't you?

According to your logs fragment lifecycle events like Fragment.onCreate() are called again after the original fragment has been restored. This strongly indicates that you are creating an entirely new DashboardFragment and replace it with the previous one.

Do you do something like:

class MyActivity extends Activity {
    public void onCreate(Bundle saved){
       super.onCreate(saved);
       if (saved == null) )
          // Ensures that you only add one fragment the very first time the Activity starts
          getSupportFragmentManager()
              .beginTransaction()
              .replace(R.id.container, new DashboardFragment())
              .commit();
       }
    }
}

Please check if you have such a "Add fragment if activity starts for the first time". Also you can add a break point to DashboardFragment.onCreateView() and then start the debugger and rotate your device. I think that you will see that there are 2 different instances of DashboardFragment.



来源:https://stackoverflow.com/questions/42364207/mvpviewstatefragment-not-restoring-viewstate-on-screen-orientation

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!