Repository navigation
Order of calling @AfterViews annotated methods from super classes #810
Description
Activity
You should not rely on the generation order at all! This is what i do for make sure the order is correct:
@EActivity public class Parent extends Activity { @AfterViews protected void afterViews() { // do here something related to parent } }
@EActivity public class Child extends Parent { @Override // no @AfterViews ! protected void afterViews() { super.afterViews(); // does something related to parent // do here something related to child } }
Reacted by Luong Vo (Lucas)I think the problem here is incremental build. We can't know in which order classes will be processed. As we add
@AfterInit/@AfterInjectmethods calls in the generated class each time we hit a method annotated with this, the order isn't guaranteed.However, we really should find a way to fix this. I'm planning this for 3.1.
Cool. That would be great, especially with Android Studio gaining more
traction.I found some way around it, but as with every way around it's not perfect ;)
On Fri, Jan 10, 2014 at 6:00 PM, Damien notifications@github.com wrote:
I think the problem here is incremental build. We can't know in which
order classes will be processed. As we add @AfterInit/@AfterInjectmethods calls in the generated class each time we hit a method annotated
with this, the order isn't guaranteed.However, we really should find a way to fix this. I'm planning this for
3.1.—
Reply to this email directly or view it on GitHubhttps://github.com//issues/810#issuecomment-32015187
.Pozdrawiam / Greetings,
Antoni Mysliborski
http://mysliborski.com/blogI ran into this same problem and it took me forever to figure out what was going on, good fix @WonderCsabo
What about a priority system? you define a
priorityon the@AfterXXXannotation.- default
priorityis 0 - a higher priority value results in an earlier call
- if two or more methods have the same priority, the call order is random (as it is now)
e.g.
@EActivity public class Parent extends Activity { @AfterViews(priority=10) protected void parent10() { // do here something related to parent } @AfterViews(priority=20) protected void parent20() { // do here something related to parent } @AfterViews(priority=0) // 0 = default protected void parent0() { // do here something related to parent } }
@EActivity public class Child extends Parent { @AfterViews(priority = 5) protected void child5() { } @AfterViews(priority = 10) protected void child10() { } @AfterViews(priority = 15) protected void child15() { } @AfterViews(priority=0) // 0 = default protected void child0() { // do here something related to parent } }
call order:
parent20(); child15(); child10(); // random order here! parent10(); // random order here! child5(); parent0(); // random order here! child0(); // random order here!
while i'm sure that this is possible, i'm not sure how much work it is for current AA implementation of code generation. i tried to understand what happens after proccessing but for the short time i had to dig in the code i was not able to understand it. ;)
my current theory (correct me if i'm wrong) the generating part of AA at some point calls
BaseGeneratedClassHolder.getGeneratedClass()and writes the code to a file.i think we could add the
@AfterXXXnot directly to a method body/block but to a list of calls or better a map of list likeMap<Integer, List<JInvocation>>and before getting the generated class for source generation we have anowAddAllTheCallsToThierCorrectPosition()that adds the calls from that map to thier corresponding method body/block.thoughts?
- default
Actually i am not really sure we should handle this. My comment solves this in the plain old inheritance way, which is more cleaner than your proposal, also does not let the user to totally ignore the class hiearchy.
and an alternative way to handle the
priorityvalue (in this case maybe with a diffrent name)- default
priorityis somewhere > 0 (100 or 1000?) - a higher priority value results in a later call call
- if two or more methods have the same priority, the call order is random (as it is now)
the example from above would result in an order like this
parent0(); // random order here! child0(); // random order here! child5(); child10(); // random order here! parent10(); // random order here! child15(); parent20();
while writing the previous comment i thought that this order feels a bit better
and i think this way it is easier to have something like
priority levels 100, 200, 300 with one method each in the parent class. here you can say in what order these methods have to be called to correctly work for the parent classes and child classes have enough priority levels in between to call methods before and/or after a certain parent method.- default
@WonderCsabo i can understand your point
and although i'm 100% not sure if this is really needed i still think that there could be some use cases where this could be usefull.
But well, my job here is not to decide what to implement (and how). i'm here to suggest what could be done and maybe write some code to get it done.
I just gave this issue some brain time as @DayS said
However, we really should find a way to fix this. I'm planning this for 3.1.
No worries, thanks for sharing all your thoughts here, ideas are always welcomed. I have several problems with this issue:
- i do not really like the possibilities how can we fix this
- we already can use it as i illustrated, and that method is quiet clean
- reordering implementation can be really hard, since in incremental compilation we can only access the current class... Also to implement this we should alter the architecture of AA.
This solution makes the annotation complicated because we have to know what the value of the priority in the annotated methods in the hierarchy.
AA is made to make code cleaner, not to complicate it.
Then, it's not written that we guaranty any order. (Maybe we should write in the wiki that the order is random).
Finally, the example given by @WonderCsabo has a clean code and solve this problem so we shouldn't provide anything else.One thing we maybe should do is, in the example given by @WonderCsabo, if the method
afterViewsofChildis annotated with@AfterViews, we generate only one call toafterViews()in the generated class (actually we generate two calls).Okay. This looks like a decision.
I suggest to close this issue with a
wontfixlabel and create a new issue to update the wiki to explicitly mention that all three@AfterXXXannotations do not guarantee an calling order beside thier actually when to call rules like@AfterInjectonce after the@Beanetc stuff got injected.also there should be an issue for the two calls that get generated as @yDelouis mentioned
BTW in incremental compilation do we access properties of the superclass?
This is a wonftix. The doc should be updated though.
I have such inheritance hierarchy:
A -> B -> C (both A and B are abstract activities/fragments).
All classes have methods with @Afterviews annotations - lets say initA, initB and initC
What I have noticed, if I just compile project (I'm using AndroidStudio, but as I remember I had similar problem in Eclipse), after changing something in class B, methods will be called in order:
initB, initA, initC
After clean rebuild i get the correct order:
initA, initB, initC - until I change again something in B
I think they should always be called in order consistent with inheritance hierarchy, otherwise it causes lots of unexpected bugs if i forget to do clean rebuild