Last active
June 9, 2016 17:27
-
-
Save senneco/c659a7022ffbab4ee970884c8c62f3ee to your computer and use it in GitHub Desktop.
Fix bug of mvp delegate
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.arellomobile.mvp; | |
import java.util.ArrayList; | |
import java.util.List; | |
import android.os.Bundle; | |
import com.arellomobile.mvp.presenter.PresenterType; | |
/** | |
* Date: 18-Dec-15 | |
* Time: 13:51 | |
* <p> | |
* This class represents a delegate which you can use to extend Mvp's support to any class. | |
* <p> | |
* When using an {@link FixedMvpDelegate}, lifecycle methods which should be proxied to the delegate: | |
* <ul> | |
* <li>{@link #onCreate(Bundle)}</li> | |
* <li>{@link #onStart()}</li> | |
* <li>{@link #onSaveInstanceState(android.os.Bundle)}</li> | |
* <li>{@link #onStop()}</li> | |
* <li>{@link #onDestroy()}</li> | |
* </ul> | |
* <p> | |
* Every {@link Object} can only be linked with one {@link FixedMvpDelegate} instance, | |
* so the instance returned from {@link #FixedMvpDelegate(Object)}} should be kept | |
* until the Object is destroyed. | |
* | |
* @author Alexander Blinov | |
*/ | |
public class FixedMvpDelegate<Delegated> | |
{ | |
private static final String KEY_TAGS = "com.arellomobile.mvp.MvpDelegate.KEY_TAGS"; | |
private String mKeyTags = KEY_TAGS; | |
private String mDelegateTag; | |
private final Delegated mDelegated; | |
private int mStateSavedCounter; | |
private boolean mIsAttached; | |
private FixedMvpDelegate mParentDelegate; | |
private List<MvpPresenter<? super Delegated>> mPresenters; | |
private List<FixedMvpDelegate> mChildDelegates; | |
private Bundle mBundle; | |
public FixedMvpDelegate(Delegated delegated) | |
{ | |
mDelegated = delegated; | |
mChildDelegates = new ArrayList<>(); | |
} | |
public void setParentDelegate(FixedMvpDelegate 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 it already has child presenters"); | |
} | |
mParentDelegate = delegate; | |
mKeyTags = mParentDelegate.mKeyTags + "$" + childId; | |
delegate.addChildDelegate(this); | |
} | |
private void addChildDelegate(FixedMvpDelegate delegate) | |
{ | |
mChildDelegates.add(delegate); | |
} | |
/** | |
* <p>Similar like {@link #onCreate(Bundle)}. But this method try to get saved | |
* state from parent presenter before get presenters</p> | |
*/ | |
public void onCreate() | |
{ | |
Bundle bundle = new Bundle(); | |
if (mParentDelegate != null) | |
{ | |
bundle = mParentDelegate.mBundle; | |
} | |
onCreate(bundle); | |
} | |
/** | |
* <p>Get(or create if not exists) presenters for delegated object and bind | |
* them to this object fields</p> | |
* | |
* @param bundle with saved state | |
*/ | |
public void onCreate(Bundle bundle) | |
{ | |
mStateSavedCounter = 0; | |
mIsAttached = false; | |
mBundle = bundle; | |
//get base tag for presenters | |
if (bundle == null || !mBundle.containsKey(mKeyTags)) | |
{ | |
mDelegateTag = generateTag(); | |
} | |
else | |
{ | |
mDelegateTag = bundle.getString(mKeyTags); | |
} | |
//bind presenters to view | |
mPresenters = MvpFacade.getInstance().getMvpProcessor().getMvpPresenters(mDelegated, mDelegateTag); | |
for (FixedMvpDelegate childDelegate : mChildDelegates) | |
{ | |
childDelegate.onCreate(bundle); | |
} | |
} | |
/** | |
* <p>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</p> | |
*/ | |
public void onStart() | |
{ | |
mStateSavedCounter = 0; | |
for (MvpPresenter<? super Delegated> presenter : mPresenters) | |
{ | |
if (mIsAttached && presenter.getAttachedViews().contains(mDelegated)) | |
{ | |
continue; | |
} | |
presenter.attachView(mDelegated); | |
} | |
for (FixedMvpDelegate<?> childDelegate : mChildDelegates) | |
{ | |
childDelegate.onStart(); | |
} | |
mIsAttached = true; | |
} | |
public void onStop() | |
{ | |
for (FixedMvpDelegate<?> childDelegate : mChildDelegates) | |
{ | |
childDelegate.onStop(); | |
} | |
} | |
/** | |
* <p>Detach delegated object from their presenters and destroy presenters if | |
* they are not needed.</p> | |
*/ | |
public void onDestroy() | |
{ | |
for (MvpPresenter<? super Delegated> presenter : mPresenters) | |
{ | |
presenter.detachView(mDelegated); | |
} | |
if (mStateSavedCounter == 0) | |
{ | |
destroyPresenters(); | |
} | |
mStateSavedCounter = Math.max(mStateSavedCounter - 1, 0); | |
for (FixedMvpDelegate<?> childDelegate : mChildDelegates) | |
{ | |
childDelegate.onDestroy(); | |
} | |
} | |
/** | |
* 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) | |
{ | |
mStateSavedCounter++; | |
outState.putString(mKeyTags, mDelegateTag); | |
for (FixedMvpDelegate childDelegate : mChildDelegates) | |
{ | |
childDelegate.onSaveInstanceState(outState); | |
} | |
} | |
private void destroyPresenters() | |
{ | |
PresenterStore presenterStore = MvpFacade.getInstance().getPresenterStore(); | |
for (MvpPresenter<?> presenter : mPresenters) | |
{ | |
if (presenter.getPresenterType() == PresenterType.LOCAL) | |
{ | |
presenter.onDestroy(); | |
presenterStore.remove(PresenterType.LOCAL, presenter.getTag(), presenter.getClass()); | |
} | |
} | |
} | |
/** | |
* @return generated tag in format: Delegated_class_full_name$MvpDelegate@hashCode | |
* | |
* example: com.arellomobile.com.arellomobile.mvp.sample.SampleFragment$MvpDelegate@32649b0 | |
*/ | |
private String generateTag() | |
{ | |
return mDelegated.getClass().getName() + "$" + getClass().getSimpleName()+ toString().replace(getClass().getName(),""); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package net.senneco.mvpfragment; | |
import android.os.Bundle; | |
import android.support.v4.app.Fragment; | |
import android.view.LayoutInflater; | |
import android.view.View; | |
import android.view.ViewGroup; | |
import com.arellomobile.mvp.FixedMvpDelegate; | |
/** | |
* Created by senneco on 09.06.2016 | |
*/ | |
public class MvpFragment extends Fragment | |
{ | |
private Bundle mTemporaryBundle;// required for view destroy/restore | |
private FixedMvpDelegate<? extends MvpFragment> mFixedMvpDelegate; | |
public MvpFragment() | |
{ | |
mTemporaryBundle = null; | |
} | |
public void onCreate(Bundle savedInstanceState) | |
{ | |
super.onCreate(savedInstanceState); | |
getMvpDelegate().onCreate(savedInstanceState); | |
} | |
@Override | |
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) | |
{ | |
if (mTemporaryBundle != null) | |
{ | |
getMvpDelegate().onCreate(mTemporaryBundle); | |
mTemporaryBundle = null; | |
} | |
return super.onCreateView(inflater, container, savedInstanceState); | |
} | |
public void onStart() | |
{ | |
super.onStart(); | |
getMvpDelegate().onStart(); | |
} | |
public void onSaveInstanceState(Bundle outState) | |
{ | |
super.onSaveInstanceState(outState); | |
getMvpDelegate().onSaveInstanceState(outState); | |
} | |
public void onStop() | |
{ | |
super.onStop(); | |
getMvpDelegate().onStop(); | |
} | |
@Override | |
public void onDestroyView() | |
{ | |
super.onDestroyView(); | |
mTemporaryBundle = new Bundle(); | |
getMvpDelegate().onSaveInstanceState(mTemporaryBundle); | |
getMvpDelegate().onDestroy(); | |
} | |
@Override | |
public void onDestroy() | |
{ | |
super.onDestroy(); | |
getMvpDelegate().onDestroy(); | |
} | |
public FixedMvpDelegate getMvpDelegate() | |
{ | |
if (mFixedMvpDelegate == null) | |
{ | |
mFixedMvpDelegate = new FixedMvpDelegate<>(this); | |
} | |
return mFixedMvpDelegate; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment