/* * Copyright 2015 Hannes Dorfmann. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.hannesdorfmann.mosby3.mvp.delegate; import android.os.Bundle; import android.support.v4.app.Fragment; import android.util.Log; import android.view.View; import com.hannesdorfmann.mosby3.PresenterManager; import com.hannesdorfmann.mosby3.mvp.MvpPresenter; import com.hannesdorfmann.mosby3.mvp.MvpView; import com.hannesdorfmann.mosby3.mvp.viewstate.RestorableViewState; import com.hannesdorfmann.mosby3.mvp.viewstate.ViewState; /** * The {@link FragmentMvpDelegateImpl} with {@link ViewState} support * * @author Hannes Dorfmann * @since 1.1.0 */ public class FragmentMvpViewStateDelegateImpl<V extends MvpView, P extends MvpPresenter<V>, VS extends ViewState<V>> extends FragmentMvpDelegateImpl<V, P> { public static boolean DEBUG = false; private static final String DEBUG_TAG = "FragmentMvpDelegateImpl"; private MvpViewStateDelegateCallback<V, P, VS> delegateCallback; private boolean applyViewState = false; private boolean applyViewStateFromMemory = false; public FragmentMvpViewStateDelegateImpl(Fragment fragment, MvpViewStateDelegateCallback<V, P, VS> delegateCallback, boolean keepPresenterAndViewStateDuringScreenOrientationChange, boolean keepPresenterAndViewStateOnBackstack) { super(fragment, delegateCallback, keepPresenterAndViewStateDuringScreenOrientationChange, keepPresenterAndViewStateOnBackstack); this.delegateCallback = delegateCallback; } @Override public void onViewCreated(View view, Bundle bundle) { super.onViewCreated(view, bundle); if (bundle != null && keepPresenterInstanceDuringScreenOrientationChanges) { mosbyViewId = bundle.getString(KEY_MOSBY_VIEW_ID); if (DEBUG) { Log.d(DEBUG_TAG, "MosbyView ID = " + mosbyViewId + " for MvpView: " + delegateCallback.getMvpView()); } } if (mosbyViewId != null) { VS viewState = PresenterManager.getViewState(fragment.getActivity(), mosbyViewId); if (viewState != null) { // // ViewState restored from PresenterManager // delegateCallback.setViewState(viewState); applyViewState = true; applyViewStateFromMemory = true; if (DEBUG) { Log.d(DEBUG_TAG, "ViewState reused from Mosby internal cache for view: " + delegateCallback.getMvpView() + " viewState: " + viewState); } return; } } VS viewState = delegateCallback.createViewState(); if (viewState == null) { throw new NullPointerException( "ViewState returned from createViewState() is null! MvpView that has returned null as ViewState is: " + delegateCallback.getMvpView()); } if (bundle != null && viewState instanceof RestorableViewState) { // A little bit hacky that we need an instance of the viewstate to restore a view state // (may creates another view state object) but I don't know any better way :) RestorableViewState restoredViewState = ((RestorableViewState) viewState).restoreInstanceState(bundle); if (restoredViewState != null) { // // ViewState restored from bundle // viewState = (VS) restoredViewState; delegateCallback.setViewState(viewState); applyViewState = true; applyViewStateFromMemory = false; if (keepPresenterInstanceDuringScreenOrientationChanges) { if (mosbyViewId == null) { throw new IllegalStateException( "The (internal) Mosby View id is null although bundle is not null. This should never happen. This seems to be a Mosby internal error. Please report this issue at https://github.com/sockeqwe/mosby/issues"); } PresenterManager.putViewState(fragment.getActivity(), mosbyViewId, viewState); } if (DEBUG) { Log.d(DEBUG_TAG, "Recreated ViewState from bundle for view: " + delegateCallback.getMvpView() + " viewState: " + viewState); } return; } } // // Entirely new ViewState has been created, typically because the app is starting the first time // if (keepPresenterInstanceDuringScreenOrientationChanges) { if (mosbyViewId == null) { throw new IllegalStateException( "The (internal) Mosby View id is null. This should never happen. This seems to be a Mosby internal error. Please report this issue at https://github.com/sockeqwe/mosby/issues"); } PresenterManager.putViewState(fragment.getActivity(), mosbyViewId, viewState); } delegateCallback.setViewState(viewState); applyViewState = false; applyViewStateFromMemory = false; if (DEBUG) { Log.d(DEBUG_TAG, "Created a new ViewState instance for view: " + delegateCallback.getMvpView() + " viewState: " + viewState); } } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); if (applyViewState) { VS viewState = delegateCallback.getViewState(); V mvpView = delegateCallback.getMvpView(); if (viewState == null) { throw new NullPointerException( "ViewState returned from getViewState() is null! MvpView " + mvpView); } delegateCallback.setRestoringViewState(true); viewState.apply(mvpView, applyViewStateFromMemory); delegateCallback.setRestoringViewState(false); delegateCallback.onViewStateInstanceRestored(applyViewStateFromMemory); } else { delegateCallback.onNewViewStateInstance(); } } @Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); boolean keepInstance = retainPresenterInstance(); VS viewState = delegateCallback.getViewState(); if (viewState == null) { throw new NullPointerException( "ViewState returned from getViewState() is null! The MvpView that has returned null in getViewState() is " + delegateCallback.getMvpView()); } if (keepInstance && viewState instanceof RestorableViewState) { ((RestorableViewState) viewState).saveInstanceState(outState); } } }