-
Notifications
You must be signed in to change notification settings - Fork 1.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Inflation crash when using Mortar #135
Comments
Any help on this one? |
I think someone else raised this? I use Mortar fine. I can only suggest this is a config issue :/ Without seeing how you included Mortar into your project, its hard to take a guess what's going on.
That error suggestions its out of my hands, I would check that you are providing the correct scope/graph to your system service in your activity. |
This error does not occur if I call CalligraphyConfig.Builder#disableCustomViewInflation() , but now all my custom views must have Calligraphy fonts set programatically. Does Calligraphy ever interfere with Dagger? |
Calligraphy has no knowledge of Dagger. I use CustomView inflation with Dagger+Mortar+Flow. I inflate screens the following way. public void showScreen(S screen, Flow.Direction direction, final Backstack newBackstack, final Flow.Callback callback) {
MortarScope activityScope = Mortar.getScope(context);
MortarScope newChildScope = activityScope.requireChild(screen);
View oldChild = getActiveView();
View newChild;
Timber.d("Show Blueprint: %s", newChildScope.getName());
if (oldChild != null) {
MortarScope oldChildScope = Mortar.getScope(oldChild.getContext());
Timber.d("Hide Blueprint: %s", oldChildScope.getName());
if (oldChildScope.getName().equals(screen.getMortarScopeName())) {
// If it's already showing, short circuit.
return;
}
// Destroy the old scope, this gets a bit racy
activityScope.destroyChild(oldChildScope);
}
// Create the new child.
Context childContext = newChildScope.createContext(context);
newChild = Layouts.createView(childContext, screen);
displayView(oldChild, newChild, direction, callback);
}
|
And for full disclosure this is how my FlowActivity works: /**
* Created by chris on 06/01/2014
*/
public abstract class FlowActivity extends ActionBarActivity {
/**
* Mortar Scope
*/
private MortarActivityScope mActivityScope;
private String mActivityScopeName;
/**
* Current flow stack
*/
protected Flow mActivityFlow;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (isWrongInstance()) {
finish();
return;
}
// Action Bar
supportRequestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
//--
// Gets Parent Scope From Application via SystemService
MortarScope parentScope = Mortar.getScope(getApplication());
mActivityScope = Mortar.requireActivityScope(parentScope, getActivityBlueprint(getActivityScopeName()));
Mortar.inject(this, this);
mActivityScope.onCreate(savedInstanceState);
setContentView(getActivityBlueprintContentRes());
ButterKnife.inject(this);
// Find the Container
final View view = ButterKnife.findById(this, R.id.container);
if (!(view instanceof HasFlow))
throw new RuntimeException("The Activities Blueprint Screen, must implement FlowView");
final HasFlow hasFlow = (HasFlow) view;
mActivityFlow = hasFlow.getFlow();
}
@Override
protected void onSaveInstanceState(@NonNull final Bundle outState) {
super.onSaveInstanceState(outState);
if (mActivityScope != null && !mActivityScope.isDestroyed())
mActivityScope.onSaveInstanceState(outState);
}
@Override
public Object onRetainCustomNonConfigurationInstance() {
if (mActivityScope != null)
return mActivityScope.getName();
return super.onRetainCustomNonConfigurationInstance();
}
@Override
protected void onActivityResult(final int requestCode, final int resultCode, final Intent data) {
super.onActivityResult(requestCode, resultCode, data);
mActivityResultHelper.onActivityResult(requestCode, resultCode, data);
}
@Override
protected void onDestroy() {
super.onDestroy();
if (!isChangingConfigurations() && mActivityScope != null) {
MortarScope parentScope = Mortar.getScope(getApplication());
parentScope.destroyChild(mActivityScope);
mActivityScope = null;
}
mActivityResultHelper = null;
}
/**
* Inform the view about back events.
*/
@Override
public void onBackPressed() {
// Give the view a chance to handle going back. If it declines the honor, let super do its thing.
if (!mActivityFlow.goBack()) super.onBackPressed();
}
@Override
protected void attachBaseContext(@NonNull Context newBase) {
super.attachBaseContext(CalligraphyContextWrapper.wrap(newBase));
}
/**
* Return a Unique Scope name per instance of this Activity, should reduce overlapping activity
* Scope Name Conflict Issues!
*/
protected String getActivityScopeName() {
if (mActivityScopeName == null)
mActivityScopeName = (String) getLastCustomNonConfigurationInstance();
if (mActivityScopeName == null) {
mActivityScopeName = getClass().getName() + "-" + UUID.randomUUID().toString();
}
return mActivityScopeName;
}
/**
* <b>MUST<b> contain {@link com.justyoyo.ui.mortar.utils.HasFlow} with ID
* {@link R.id#container}
*/
protected abstract int getActivityBlueprintContentRes();
/**
* Return the Blueprint for this Activity which supports the subviews.
* This contains the flow stuff.
* <p/>
* Inherit you concrete {@link mortar.Blueprint} from
* {@link com.justyoyo.ui.mortar.core.Main}
*
* @param activityScopeName
*/
protected abstract Blueprint getActivityBlueprint(final String activityScopeName);
@Override
public Object getSystemService(@NonNull String name) {
if (Mortar.isScopeSystemService(name)) {
return mActivityScope;
}
return super.getSystemService(name);
}
/**
* Dev tools and the play store (and others?) launch with a different intent, and so
* lead to a redundant instance of this activity being spawned. <a
* href="http://stackoverflow.com/questions/17702202/find-out-whether-the-current-activity-will-be-task-root-eventually-after-pendin"
* >Details</a>.
*/
private boolean isWrongInstance() {
if (!isTaskRoot()) {
Intent intent = getIntent();
boolean isMainAction = intent.getAction() != null && intent.getAction().equals(ACTION_MAIN);
return intent.hasCategory(CATEGORY_LAUNCHER) && isMainAction;
}
return false;
}
} Hopefully that will help. |
I have discovered the issue. Thank you for all this nice code to reference. We have almost identical implementation, but with one difference. Instead of using Layout.createView(), we copied the code from Layout.createView() and modified it from: /** Create an instance of the view specified in a {@link Layout} annotation. */
public static android.view.View createView(Context context, Object screen) {
return createView(context, screen.getClass());
}
/** Create an instance of the view specified in a {@link Layout} annotation. */
public static android.view.View createView(Context context, Class<?> screenType) {
Layout screen = screenType.getAnnotation(Layout.class);
if (screen == null) {
throw new IllegalArgumentException(
String.format("@%s annotation not found on class %s", Layout.class.getSimpleName(),
screenType.getName()));
}
int layout = screen.value();
return inflateLayout(context, layout);
}
private static android.view.View inflateLayout(Context context, int layoutId) {
return LayoutInflater.from(context).inflate(layoutId, null);
}
private Layouts() {
} To: /** Create an instance of the view specified in a {@link flow.Layout} annotation. */
private static android.view.View createView(Context context, Object screen, ViewGroup container) {
return createView(context, screen.getClass(), container);
}
/** Create an instance of the view specified in a {@link flow.Layout} annotation. */
private static android.view.View createView(Context context, Class<?> screenType,
ViewGroup container) {
Layout screen = screenType.getAnnotation(Layout.class);
if (screen == null) {
throw new IllegalArgumentException(
String.format("@%s annotation not found on class %s", Layout.class.getSimpleName(),
screenType.getName()));
}
int layout = screen.value();
return inflateLayout(context, layout, container);
}
private static android.view.View inflateLayout(Context context, int layoutId,
ViewGroup container) {
return LayoutInflater.from(context).inflate(layoutId, container, false);
} We did this so layout margins applied to the child views worked correctly. I can find a work around for this, but this is a bug in Calligraphy. It seems when |
The following crash occurs on the first view inflation unless CalligraphyConfig.Builder#disableCustomViewInflation() is called during initialization.
The text was updated successfully, but these errors were encountered: