All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.taig.android.mosby.delegate.DialogFragmentMvpViewStateDelegateImpl Maven / Gradle / Ivy

package io.taig.android.mosby.delegate;

import android.app.Activity;
import android.app.Fragment;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
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.delegate.FragmentMvpDelegate;
import com.hannesdorfmann.mosby3.mvp.delegate.MvpViewStateDelegateCallback;
import com.hannesdorfmann.mosby3.mvp.viewstate.RestorableViewState;
import com.hannesdorfmann.mosby3.mvp.viewstate.ViewState;

import java.util.UUID;

/**
 * The {@link FragmentMvpDelegateImpl} with {@link ViewState} support.
 *
 * 

* Attaches and restores ViewState in {@link #onStart()} * (also {@link MvpViewStateDelegateCallback#onNewViewStateInstance()} or {@link * MvpViewStateDelegateCallback#onViewStateInstanceRestored(boolean)} will be called from {@link * #onStop()}). * View is detached from presenter in {@link #onStop()}. Finally, {@link MvpPresenter#destroy()} * is called from {@link #onDestroy()} (if Fragment will be destoryed permanently, not screen * orientation changes). *

* *

* Presenter should be used only after {@link #onStart()}. Since the ViewState feature has its own * lifecycle (kind of) {@link MvpViewStateDelegateCallback#onNewViewStateInstance()} or {@link * MvpViewStateDelegateCallback#onViewStateInstanceRestored(boolean)} you should only use those 2 * methods to start an operation like "loading data". *

* * @author Hannes Dorfmann * @since 1.1.0 */ public class DialogFragmentMvpViewStateDelegateImpl, VS extends ViewState> implements DialogFragmentMvpDelegate { protected static final String KEY_MOSBY_VIEW_ID = "com.hannesdorfmann.mosby3.fragment.mvp.id"; public static boolean DEBUG = false; private static final String DEBUG_TAG = "FragmentMvpDelegateImpl"; private MvpViewStateDelegateCallback delegateCallback; private boolean applyViewState = false; private boolean applyViewStateFromMemory = false; protected Fragment fragment; protected final boolean keepPresenterInstanceDuringScreenOrientationChanges; protected final boolean keepPresenterOnBackstack; protected String mosbyViewId; public DialogFragmentMvpViewStateDelegateImpl( Fragment fragment, MvpViewStateDelegateCallback delegateCallback, boolean keepPresenterAndViewStateDuringScreenOrientationChange, boolean keepPresenterAndViewStateOnBackstack) { this.delegateCallback = delegateCallback; if (delegateCallback == null) { throw new NullPointerException("MvpDelegateCallback is null!"); } if (fragment == null) { throw new NullPointerException("Fragment is null!"); } if (!keepPresenterAndViewStateDuringScreenOrientationChange && keepPresenterAndViewStateOnBackstack) { throw new IllegalArgumentException("It is not possible to keep the presenter on backstack, " + "but NOT keep presenter through screen orientation changes. Keep presenter on backstack also " + "requires keep presenter through screen orientation changes to be enabled"); } this.fragment = fragment; this.delegateCallback = delegateCallback; this.keepPresenterInstanceDuringScreenOrientationChanges = keepPresenterAndViewStateDuringScreenOrientationChange; this.keepPresenterOnBackstack = keepPresenterAndViewStateOnBackstack; } @Override public void onCreate(Bundle 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()); } P presenter = restorePresenterOrRecreateNewPresenterAfterProcessDeath(); delegateCallback.setPresenter(presenter); VS viewState = restoreViewStateOrRecreateViewStateAfterProcessDeath(bundle); delegateCallback.setViewState(viewState); } else { // starting for the first time P presenter = createViewIdAndPresenter(); delegateCallback.setPresenter(presenter); VS viewState = createViewState(); delegateCallback.setViewState(viewState); } // // if config change and not retaining fragment, // we have to do this here because if Fragment is on backstack or in ViewPager with FragmentPagerAdapter // a fragment (not visible) runs only the following callbacks: // 1. onCreate() // 2. onSaveInstnaceState() // 3. onDestroy(); // // Creating the View (UI) like Fragment.onViewCreate() is not triggered if Fragment not visible. // } @Override public void onCreateDialog( @Nullable Bundle savedInstanceState ) { } @Override public void onCreateView() { } @Override public void onStart() { 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.getPresenter().attachView(delegateCallback.getMvpView()); if (DEBUG) { Log.d(DEBUG_TAG, "View" + delegateCallback.getMvpView() + " attached to Presenter " + delegateCallback.getPresenter()); } if (applyViewState) { if (!applyViewStateFromMemory && 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"); } // Put viewState from bundle into Memory Cache / Presenter Manager PresenterManager.putViewState(fragment.getActivity(), mosbyViewId, delegateCallback.getViewState()); } delegateCallback.onViewStateInstanceRestored(applyViewStateFromMemory); } else { delegateCallback.onNewViewStateInstance(); } } @Override public void onStop() { delegateCallback.getPresenter().detachView(); if (DEBUG) { Log.d(DEBUG_TAG, "detached MvpView from Presenter. MvpView " + delegateCallback.getMvpView() + " Presenter: " + delegateCallback.getPresenter()); } if (keepPresenterInstanceDuringScreenOrientationChanges) { // Ensure that viewstate will be applied again after backstack navigation or view pager swipe applyViewState = true; applyViewStateFromMemory = true; } else { applyViewState = false; applyViewStateFromMemory = false; } } @Override public void onDestroy() { Activity activity = getActivity(); boolean retainPresenterInstance = FragmentMvpDelegateImpl.retainPresenterInstance(activity, fragment, keepPresenterInstanceDuringScreenOrientationChanges, keepPresenterOnBackstack); P presenter = delegateCallback.getPresenter(); if (!retainPresenterInstance) { presenter.destroy(); if (DEBUG) { Log.d(DEBUG_TAG, "Presenter destroyed. MvpView " + delegateCallback.getMvpView() + " Presenter: " + presenter); } } if (!retainPresenterInstance && mosbyViewId != null) { // mosbyViewId is null if keepPresenterInstanceDuringScreenOrientationChanges == false PresenterManager.remove(activity, mosbyViewId); } } @Override public void onSaveInstanceState(Bundle outState) { if ((keepPresenterInstanceDuringScreenOrientationChanges || keepPresenterOnBackstack) && outState != null) { outState.putString(KEY_MOSBY_VIEW_ID, mosbyViewId); if (DEBUG) { Log.d(DEBUG_TAG, "Saving MosbyViewId into Bundle. ViewId: " + mosbyViewId); } } boolean keepInstance = FragmentMvpDelegateImpl.retainPresenterInstance(getActivity(), fragment, keepPresenterInstanceDuringScreenOrientationChanges, keepPresenterOnBackstack); 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); } } @Override public void onDestroyView() { } @Override public void onPause() { } @Override public void onResume() { } @Override public void onActivityCreated(Bundle savedInstanceState) { } @Override public void onAttach(Activity activity) { } @Override public void onDetach() { } /** * Creates the presenter instance if not able to reuse presenter from PresenterManager */ private P restorePresenterOrRecreateNewPresenterAfterProcessDeath() { P presenter; if (keepPresenterInstanceDuringScreenOrientationChanges) { if (mosbyViewId != null && (presenter = PresenterManager.getPresenter(getActivity(), mosbyViewId)) != null) { // // Presenter restored from cache // if (DEBUG) { Log.d(DEBUG_TAG, "Reused presenter " + presenter + " for view " + delegateCallback.getMvpView()); } return presenter; } else { // // No presenter found in cache, most likely caused by process death // presenter = createViewIdAndPresenter(); if (DEBUG) { Log.d(DEBUG_TAG, "No presenter found although view Id was here: " + mosbyViewId + ". Most likely this was caused by a process death. New Presenter created" + presenter + " for view " + delegateCallback.getMvpView()); } return presenter; } } else { // // starting first time, so create a new presenter // presenter = createViewIdAndPresenter(); if (DEBUG) { Log.d(DEBUG_TAG, "New presenter " + presenter + " for view " + delegateCallback.getMvpView()); } return presenter; } } @NonNull private Activity getActivity() { Activity activity = fragment.getActivity(); if (activity == null) { throw new NullPointerException( "Activity returned by Fragment.getActivity() is null. Fragment is " + fragment); } return activity; } private P createViewIdAndPresenter() { P presenter = delegateCallback.createPresenter(); if (presenter == null) { throw new NullPointerException( "Presenter returned from createPresenter() is null. Fragment is " + fragment); } if (keepPresenterInstanceDuringScreenOrientationChanges) { mosbyViewId = UUID.randomUUID().toString(); PresenterManager.putPresenter(getActivity(), mosbyViewId, presenter); } return presenter; } /** * Creates a new ViewState instance * * @return the newly created instance */ private VS createViewState() { VS viewState = delegateCallback.createViewState(); if (viewState == null) { throw new NullPointerException( "ViewState returned from createViewState() is null. Fragment is " + fragment); } if (keepPresenterInstanceDuringScreenOrientationChanges) { PresenterManager.putViewState(getActivity(), mosbyViewId, viewState); } return viewState; } private VS restoreViewStateOrRecreateViewStateAfterProcessDeath(Bundle bundle) { if (bundle == null) { throw new NullPointerException("Bundle is null. This should never be the case" + "Please report this issue at https://github.com/sockeqwe/mosby/issues"); } if (mosbyViewId == null) { throw new NullPointerException( "The (internal) Mosby View id is null although bundle is not null. " + "This should never be the case while restoring ViewState instance. " + "Please report this issue at https://github.com/sockeqwe/mosby/issues"); } // // Try to restore ViewState from PresenterManager // VS viewState = PresenterManager.getViewState(fragment.getActivity(), mosbyViewId); if (viewState != null) { applyViewState = true; applyViewStateFromMemory = true; if (DEBUG) { Log.d(DEBUG_TAG, "ViewState reused from Mosby internal cache for view: " + delegateCallback.getMvpView() + " viewState: " + viewState); } return viewState; } // // Try to restore viewstate from bundle // 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 (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; applyViewState = true; applyViewStateFromMemory = false; if (keepPresenterInstanceDuringScreenOrientationChanges) { PresenterManager.putViewState(getActivity(), mosbyViewId, viewState); } if (DEBUG) { Log.d(DEBUG_TAG, "Recreated ViewState from bundle for view: " + delegateCallback.getMvpView() + " viewState: " + viewState); } return viewState; } } // // Entirely new ViewState has been created, typically because process death and mosby view id points to // a old id but view got a new one because of process death. // applyViewState = false; applyViewStateFromMemory = false; if (keepPresenterInstanceDuringScreenOrientationChanges) { PresenterManager.putViewState(getActivity(), mosbyViewId, viewState); } if (DEBUG) { Log.d(DEBUG_TAG, "Created a new ViewState instance for view: " + delegateCallback.getMvpView() + " viewState: " + viewState); } return viewState; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy