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

com.arellomobile.mvp.MvpDelegate Maven / Gradle / Ivy

package com.arellomobile.mvp;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import android.os.Bundle;

import com.arellomobile.mvp.presenter.PresenterType;

/**
 * Date: 18-Dec-15
 * Time: 13:51
 * 

* This class represents a delegate which you can use to extend Mvp's support to any class. *

* When using an {@link MvpDelegate}, lifecycle methods which should be proxied to the delegate: *

    *
  • {@link #onCreate(Bundle)}
  • *
  • {@link #onAttach()}: inside onStart() of Activity or Fragment
  • *
  • {@link #onSaveInstanceState(android.os.Bundle)}
  • *
  • {@link #onDetach()}: inside onDestroy() for Activity or onDestroyView() for Fragment
  • *
  • {@link #onDestroy()}
  • *
*

* Every {@link Object} can only be linked with one {@link MvpDelegate} instance, * so the instance returned from {@link #MvpDelegate(Object)}} should be kept * until the Object is destroyed. * * @author Yuri Shmakov * @author Alexander Blinov * @author Konstantin Tckhovrebov */ public class MvpDelegate { private static final String KEY_TAG = "com.arellomobile.mvp.MvpDelegate.KEY_TAG"; public static final String MOXY_DELEGATE_TAGS_KEY = "MoxyDelegateBundle"; private String mKeyTag = KEY_TAG; private String mDelegateTag; private final Delegated mDelegated; private boolean mIsAttached; private MvpDelegate mParentDelegate; private List> mPresenters; private List mChildDelegates; private Bundle mBundle; public MvpDelegate(Delegated delegated) { mDelegated = delegated; mChildDelegates = new ArrayList<>(); } public void setParentDelegate(MvpDelegate delegate, String childId) { if (mBundle != null) { throw new IllegalStateException("You should call setParentDelegate() before first onCreate()"); } if (mChildDelegates != null && mChildDelegates.size() > 0) { throw new IllegalStateException("You could not set parent delegate when there are already has child presenters"); } mParentDelegate = delegate; mKeyTag = mParentDelegate.mKeyTag + "$" + childId; delegate.addChildDelegate(this); } private void addChildDelegate(MvpDelegate delegate) { mChildDelegates.add(delegate); } private void removeChildDelegate(MvpDelegate delegate) { mChildDelegates.remove(delegate); } /** * Free self link from children list (mChildDelegates) in parent delegate * property mParentDelegate stay keep link to parent delegate for access to * parent bundle for save state in {@link #onSaveInstanceState()} */ public void freeParentDelegate() { if (mParentDelegate == null) { throw new IllegalStateException("You should call freeParentDelegate() before first setParentDelegate()"); } mParentDelegate.removeChildDelegate(this); } public void removeAllChildDelegates() { // For avoiding ConcurrentModificationException when removing by removeChildDelegate() List childDelegatesClone = new ArrayList(mChildDelegates.size()); childDelegatesClone.addAll(mChildDelegates); for (MvpDelegate childDelegate : childDelegatesClone) { childDelegate.freeParentDelegate(); } mChildDelegates = new ArrayList<>(); } /** *

Similar like {@link #onCreate(Bundle)}. But this method try to get saved * state from parent presenter before get presenters

*/ public void onCreate() { Bundle bundle = new Bundle(); if (mParentDelegate != null) { bundle = mParentDelegate.mBundle; } onCreate(bundle); } /** *

Get(or create if not exists) presenters for delegated object and bind * them to this object fields

* * @param bundle with saved state */ public void onCreate(Bundle bundle) { if (mParentDelegate == null && bundle != null) { bundle = bundle.getBundle(MOXY_DELEGATE_TAGS_KEY); } mIsAttached = false; mBundle = bundle != null ? bundle : new Bundle(); //get base tag for presenters if (bundle == null || !mBundle.containsKey(mKeyTag)) { mDelegateTag = generateTag(); } else { mDelegateTag = bundle.getString(mKeyTag); } //bind presenters to view mPresenters = MvpFacade.getInstance().getMvpProcessor().getMvpPresenters(mDelegated, mDelegateTag); for (MvpDelegate childDelegate : mChildDelegates) { childDelegate.onCreate(bundle); } } /** *

Attach delegated object as view to presenter fields of this object. * If delegate did not enter at {@link #onCreate(Bundle)}(or * {@link #onCreate()}) before this method, then view will not be attached to * presenters

*/ public void onAttach() { for (MvpPresenter presenter : mPresenters) { if (mIsAttached && presenter.getAttachedViews().contains(mDelegated)) { continue; } presenter.attachView(mDelegated); } for (MvpDelegate childDelegate : mChildDelegates) { childDelegate.onAttach(); } mIsAttached = true; } /** *

Detach delegated object from their presenters.

*/ public void onDetach() { for (MvpPresenter presenter : mPresenters) { if (!mIsAttached && !presenter.getAttachedViews().contains(mDelegated)) { continue; } presenter.detachView(mDelegated); } mIsAttached = false; for (MvpDelegate childDelegate : mChildDelegates) { childDelegate.onDetach(); } } /** *

View was being destroyed, but logical unit still alive

*/ public void onDestroyView() { for (MvpPresenter presenter : mPresenters) { presenter.destroyView(mDelegated); } // For avoiding ConcurrentModificationException when removing from mChildDelegates List childDelegatesClone = new ArrayList(mChildDelegates.size()); childDelegatesClone.addAll(mChildDelegates); for (MvpDelegate childDelegate : childDelegatesClone) { childDelegate.onDestroyView(); } if (mParentDelegate != null) { freeParentDelegate(); } } /** *

Destroy presenters.

*/ public void onDestroy() { PresentersCounter presentersCounter = MvpFacade.getInstance().getPresentersCounter(); PresenterStore presenterStore = MvpFacade.getInstance().getPresenterStore(); Set allChildPresenters = presentersCounter.getAll(mDelegateTag); for (MvpPresenter presenter : allChildPresenters) { boolean isRejected = presentersCounter.rejectPresenter(presenter, mDelegateTag); if (isRejected && presenter.getPresenterType() != PresenterType.GLOBAL) { presenterStore.remove(presenter.getTag()); presenter.onDestroy(); } } } /** *

Similar like {@link #onSaveInstanceState(Bundle)}. But this method try to save * state to parent presenter Bundle

*/ public void onSaveInstanceState() { Bundle bundle = new Bundle(); if (mParentDelegate != null && mParentDelegate.mBundle != null) { bundle = mParentDelegate.mBundle; } onSaveInstanceState(bundle); } /** * Save presenters tag prefix to save state for restore presenters at future after delegate recreate * * @param outState out state from Android component */ public void onSaveInstanceState(Bundle outState) { if (mParentDelegate == null) { Bundle moxyDelegateBundle = new Bundle(); outState.putBundle(MOXY_DELEGATE_TAGS_KEY, moxyDelegateBundle); outState = moxyDelegateBundle; } outState.putAll(mBundle); outState.putString(mKeyTag, mDelegateTag); for (MvpDelegate childDelegate : mChildDelegates) { childDelegate.onSaveInstanceState(outState); } } public Bundle getChildrenSaveState() { return mBundle; } /** * @return generated tag in format: <parent_delegate_tag> <delegated_class_full_name>$MvpDelegate@<hashCode> *

* example: com.arellomobile.mvp.sample.SampleFragment$MvpDelegate@32649b0 */ private String generateTag() { String tag = mParentDelegate != null ? mParentDelegate.mDelegateTag + " " : ""; tag += mDelegated.getClass().getSimpleName() + "$" + getClass().getSimpleName() + toString().replace(getClass().getName(), ""); return tag; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy