Open niqo01 opened 10 years ago
Do you have similar sequence of operation: orientation changed --> back pressed (leave the app) --> start the app --> orientation changed?
This is definitely the trickiest part of getting Mortar to play nice. When, where and how are you calling destroy() on your activity scope?
One thing we've noticed is that there is some kind of race in Android's launcher where a new task will be started slightly overlapping an outgoing one (IIRC you can see this by really whaling on your app icon and the back button, or maybe it's the home button). We guard against this by including the Activity's task id in its Blueprint name. Maybe we need to build that into Mortar#requireActivityScope.
@victorfu nope
@rjrjr , We call destroy()
on the activity scope in our Activity onDestroy
method as follow:
if (isFinishing() && activityScope != null) {
activityScope.destroy();
activityScope = null;
}
I ll try adding the task id to activity scope. Apparently one of my beta user can reproduce this one almost consistently. I'll let you know more soon.
@rjrjr including the Activity's task id in its Blueprint name solve the issue. Maybe including this in the sample would be nice for others.
@rjrjr your suggestion also solved my problem : )
The task id approach isn't perfect, we're still seeing the occasional problem where Android surprises us with overlapping activities that we weren't expecting. But I think @pyricau had a better idea yesterday — use onRetainNonConfigurationInstance, and a UUID in your activity scope name. We're trying it out now, and if it proves itself out I'll update the sample to demonstrate.
Something like:
boolean configurationChangeIncoming;
String scopeName;
@Override protected final void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
activityScope = Mortar.requireActivityScope(getParentScope(),
new ActivityBlueprint(getScopeName()));
activityScope.onCreate(savedInstanceState);
}
@Override public Object onRetainNonConfigurationInstance() {
configurationChangeIncoming = true;
return activityScope.getName();
}
@Override protected void onDestroy() {
if (!configurationChangeIncoming) activityScope.destroy();
}
private String getScopeName() {
if (scopeName == null) scopeName = (String) getLastNonConfigurationInstance();
if (scopeName == null) {
scopeName = getClass().getName() + "-" + UUID.randomUUID().toString();
}
return scopeName;
}
Probably can avoid this mess by using singleTask
or singleInstance
launch mode. Should confirm that, or if it's not true bring this code to the sample.
FWIW singleTask and singleInstance cannot be relied on to solve this problem.
Including taskId in the blueprint (getScopeName()) fixed my espresso tests (they create and tear down activities/mortar scopes real fast and I ended up having dead MortarScopes)
Do you have any idea on what could cause the activity scope to be destroyed before the same activity
performSaveInstanceState
is called?Crash: