/* * 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.app.Activity; import android.os.Bundle; import android.support.annotation.NonNull; import android.util.Log; 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 default implementation for {@link ActivityMvpDelegate} that supports {@link ViewState} * * @author Hannes Dorfmann * @since 1.1.0 */ public class ActivityMvpViewStateDelegateImpl<V extends MvpView, P extends MvpPresenter<V>, VS extends ViewState<V>> extends ActivityMvpDelegateImpl<V, P> { public static boolean DEBUG = false; private static final String DEBUG_TAG = "ActivityMvpViewStateDel"; private MvpViewStateDelegateCallback<V, P, VS> delegateCallback; /** * @param activity The activity * @param delegateCallback The callback * @param keepPresenterAndViewState true, if the presenter and the view state should be kept * across screen orientation changes (and if ViewState is instance of {@link RestorableViewState} * it will be saved persistently in a bundle to survive process death). Otherwise, false */ public ActivityMvpViewStateDelegateImpl(Activity activity, MvpViewStateDelegateCallback<V, P, VS> delegateCallback, boolean keepPresenterAndViewState) { super(activity, delegateCallback, keepPresenterAndViewState); this.delegateCallback = delegateCallback; } private void setViewState(@NonNull VS viewState, boolean applyViewState, boolean applyViewStateFromMemory) { if (viewState == null) { throw new IllegalStateException( "Oops, viewState is null! This seems to be a Mosby internal bug. Please report this issue at https://github.com/sockeqwe/mosby/issues"); } delegateCallback.setViewState(viewState); if (applyViewState) { delegateCallback.setRestoringViewState(true); delegateCallback.getViewState() .apply(delegateCallback.getMvpView(), applyViewStateFromMemory); delegateCallback.setRestoringViewState(false); delegateCallback.onViewStateInstanceRestored(applyViewStateFromMemory); } } @Override public void onPostCreate(Bundle bundle) { super.onPostCreate(bundle); if (mosbyViewId != null) { VS viewState = PresenterManager.getViewState(activity, mosbyViewId); if (viewState != null) { // // ViewState restored from PresenterManager // setViewState(viewState, true, 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; setViewState(viewState, true, false); if (keepPresenterInstance) { 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(activity, 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 (keepPresenterInstance) { 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(activity, mosbyViewId, viewState); } setViewState(viewState, false, false); if (DEBUG) { Log.d(DEBUG_TAG, "Created a new ViewState instance for view: " + delegateCallback.getMvpView() + " viewState: " + viewState); } delegateCallback.onNewViewStateInstance(); } @Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); boolean keepInstance = retainPresenterInstance(keepPresenterInstance, activity); 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); } } }