本文介绍了MvpViewStateFragment无法在屏幕方向上还原ViewState的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用Mosby MVP库开发一个Android应用.在一个特定的Fragment中,ViewState已实现但未使用(状态未更改或其他任何东西).一些视图逻辑是由widgetManager实现的.我正确地更改了状态,但是行为却很奇怪:在屏幕方向上,在viewState apply()之后调用createViewState()onNewViewStateInstance():这取消了恢复视图状态和相关行为的操作.

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 ?

我已经将ViewState实现为RestorableParcelableViewState,但是发生了同样的事情.

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

调试后:循环进行:onSaveInstanceState(片段),saveInstanceState(视图状态),onViewCreated(f),应用(vs),[正确的行为,然后],createViewState(f),onCreate(f),createPresenter(f ),onViewCreated(f),一切都再次为null,然后重新启动,就好像该片段是使用null savedInstanceState创建的.

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.

这是片段的核心:

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

视图状态:

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

演示者:

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

推荐答案

我认为您不小心在活动"中的每个方向更改上添加了新的DashboardFragment,不是吗?

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

根据您的日志,在还原原始片段之后,将再次调用诸如Fragment.onCreate()之类的片段生命周期事件.这强烈表明您正在创建一个全新的DashboardFragment并将其替换为上一个.

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

请检查您是否有这样的如果活动首次开始则添加片段".您也可以在DashboardFragment.onCreateView()处添加断点,然后启动调试器并旋转设备.我认为您会看到DashboardFragment的两个不同实例.

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.

这篇关于MvpViewStateFragment无法在屏幕方向上还原ViewState的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-24 14:45