I try to support MvpConstraintLayout myself, just copy code from MvpLinearLayout
public abstract class MvpConstraintLayout<V extends MvpView, P extends MvpPresenter<V>>
extends ConstraintLayout implements MvpView, ViewGroupDelegateCallback<V, P> {
protected P presenter;
protected ViewGroupMvpDelegate<V, P> mvpDelegate;
public MvpConstraintLayout(Context context) {
super(context);
}
public MvpConstraintLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MvpConstraintLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
/**
* Get the mvp delegate. This is internally used for creating presenter, attaching and detaching
* view from presenter etc.
*
* <p><b>Please note that only one instance of mvp delegate should be used per android.view.View
* instance</b>.
* </p>
*
* <p>
* Only override this method if you really know what you are doing.
* </p>
*
* @return {@link ViewGroupMvpDelegate}
*/
@NonNull
protected ViewGroupMvpDelegate<V, P> getMvpDelegate() {
if (mvpDelegate == null) {
mvpDelegate = new ViewGroupMvpDelegateImpl<>(this, true);
}
return mvpDelegate;
}
@Override protected void onAttachedToWindow() {
super.onAttachedToWindow();
getMvpDelegate().onAttachedToWindow();
}
@Override protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
getMvpDelegate().onDetachedFromWindow();
}
@SuppressLint("MissingSuperCall") @Override protected Parcelable onSaveInstanceState() {
return getMvpDelegate().onSaveInstanceState();
}
@SuppressLint("MissingSuperCall") @Override
protected void onRestoreInstanceState(Parcelable state) {
getMvpDelegate().onRestoreInstanceState(state);
}
/**
* Instantiate a presenter instance
*
* @return The {@link MvpPresenter} for this view
*/
public abstract P createPresenter();
@Override public P getPresenter() {
return presenter;
}
@Override public void setPresenter(P presenter) {
this.presenter = presenter;
}
@Override public V getMvpView() {
return (V) this;
}
@Override public final Parcelable superOnSaveInstanceState() {
return super.onSaveInstanceState();
}
@Override public final void superOnRestoreInstanceState(Parcelable state) {
super.onRestoreInstanceState(state);
}
}
Then, use it in code
public class StatusBarLayout extends MvpConstraintLayout<StatusView, StatusPresenter>
implements StatusView {
public StatusBarLayout(Context context) {
super(context);
init();
}
public StatusBarLayout(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public StatusBarLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
ButterKnife.bind(this, this);
}
@Override
public StatusPresenter createPresenter() {
return DaggerStatusBarLayoutComponent.builder().build().presenter();
}
private void init() {
View.inflate(getContext(), R.layout.layout_status, this);
}
}
In preview, the IDE said
java.lang.IllegalStateException: Could not find the surrounding Activity
at com.hannesdorfmann.mosby3.PresenterManager.getActivity(PresenterManager.java:231)
at com.hannesdorfmann.mosby3.mvp.delegate.ViewGroupMvpDelegateImpl.<init>(ViewGroupMvpDelegateImpl.java:70)
at com.skybornecn.ifdive.widgets.MvpConstraintLayout.getMvpDelegate(MvpConstraintLayout.java:55)
at com.skybornecn.ifdive.widgets.MvpConstraintLayout.onAttachedToWindow(MvpConstraintLayout.java:63)
at android.view.View.dispatchAttachedToWindow(View.java:15395)
at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:2953)
at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:2960)
at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:2960)
at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:2960)
at android.view.AttachInfo_Accessor.setAttachInfo(AttachInfo_Accessor.java:42)
at com.android.layoutlib.bridge.impl.RenderSessionImpl.inflate(RenderSessionImpl.java:333)
at com.android.layoutlib.bridge.Bridge.createSession(Bridge.java:429)
at com.android.ide.common.rendering.LayoutLibrary.createSession(LayoutLibrary.java:368)
at com.android.tools.idea.rendering.RenderTask$2.compute(RenderTask.java:567)
at com.android.tools.idea.rendering.RenderTask$2.compute(RenderTask.java:549)
at com.intellij.openapi.application.impl.ApplicationImpl.runReadAction(ApplicationImpl.java:863)
at com.android.tools.idea.rendering.RenderTask.createRenderSession(RenderTask.java:549)
at com.android.tools.idea.rendering.RenderTask.lambda$inflate$1(RenderTask.java:680)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
I have read the mosby PresenterManager, but still not know why. In addition, install to phone, the layout displayed just ok.
UPDATE: This is fixed in Mosby 3.0.1.
This is just a android tooling issue with Mosby.
The android layout editor actually instantiates a Instance of MvpConstraintLayout
to preview it in Android Studio. However, Android Studio doesn't do that by attaching a View like MvpContraintLayout
to a real Activity, but internally uses some mocked "context" alike thing. Mosby's PresenterManager internally tries to find an Activity for your MvpConstraintLayout
, but in Android Studio there is no real Activity used (as already explained) and therefore the UI editor displays this error message and when installed on the phone it works properly (because there is a real Activity used).
To fix that you have to use view.isInEditMode()
before calling the delegate like this:
public abstract class MvpConstraintLayout<V extends MvpView, P extends MvpPresenter<V>>
extends ConstraintLayout implements MvpView, ViewGroupDelegateCallback<V, P> {
...
@Override protected void onAttachedToWindow() {
super.onAttachedToWindow();
if (!isInEditMode()) getMvpDelegate().onAttachedToWindow();
}
@Override protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
if (!isInEditMode()) getMvpDelegate().onDetachedFromWindow();
}
@SuppressLint("MissingSuperCall") @Override protected Parcelable onSaveInstanceState() {
if (!isInEditMode()) return getMvpDelegate().onSaveInstanceState();
return super.onSaveInstanceState();
}
@SuppressLint("MissingSuperCall") @Override
protected void onRestoreInstanceState(Parcelable state) {
if (!isInEditMode()) getMvpDelegate().onRestoreInstanceState(state);
}
/**
* Instantiate a presenter instance
*
* @return The {@link MvpPresenter} for this view
*/
public abstract P createPresenter();
@Override public P getPresenter() {
return presenter;
}
@Override public void setPresenter(P presenter) {
this.presenter = presenter;
}
@Override public V getMvpView() {
return (V) this;
}
@Override public final Parcelable superOnSaveInstanceState() {
return super.onSaveInstanceState();
}
@Override public final void superOnRestoreInstanceState(Parcelable state) {
super.onRestoreInstanceState(state);
}
}
This is actually something ViewGroupMvpDelegate
should take care of internally. This should be fixed with Mosby 3.0.1.