Repository navigation
Generate one common class for builders #883
Description
Activity
You will still have to declare generated class in
AndroidManifest.xml.Oh, true. But rewriting manifest is much simplier. Moreover, actualy I'm not sure that there is some real need for declare them in the manifest - gradle already processes manifest and generating new one - there is no problem to inject correct components during this step.
Moreover, you don't need to declare generated class in manifest in situations:
- The class is a fragment
- The class is a bean
- The class is a view
E.g. it is awkward:
view = CallInfoItem_.build(parent.getContext());Much better would be something like this:
view = GeneratedClasses.createView(CallInfoItem.class, parent.getContext());What do you think? If you do like such way, I'll try to implement it.
I'm also currently thinking of a kin of factory for generated class based on the original one. I'd like to get ride of direct call to generated class in the code (ie:
MyActivity_.intent(...).startActivity())Yep. I'm not sure that there is some way to avoid generated intent builders, but maybe we will get some clue while implementing other classes. So, I'll try to implement some cases in order to look deeper into the problem and make a PR, ok?
It also will be useful, if the factory class will have some way to set a strategy of instantiation. In this case it will be easier to mock up objects for testing.
I know that @jeremiemartinez and @fredszaq worked on a way to have a cleaner injection mechanism. They're also based on a kind of factory to do this. It may be great to merge these two features.
Indeed both ideas seems very much alike, you can take a look at https://github.com/fredszaq/androidannotations/tree/inject for the work we've been doing on injection.
In any case, not having to explicitly use a generated class in java code seems to be a good thing !
Yeah, looks great! But actually I would like to do it in another way - iterate over array while looking for creator is not the best idea, map of class to creator would be better. I'll take a closer look on this week, it is a very good point to start at. Thanks.
I started to work on this too, but was stuck with
IntentBuildersof generated activities.
I used @Artyomcool way of doing this, with static methods of a factory class and reflexion.
You can see the it here.I'll try to implement the same thing but without reflections. Looks like I need to make @fredszaq and @yDelouis approaches work together to achieve this.
As forIntentBuildersI don't see the direct way. But what if reimplement@Extraannotation for working with POJO? I mean something like that:@EExtra class Extra { String stringExtra; int intExtra; } @EActivity class SomeActivity extends Activity { @Extra Extra extra; }This allows us to make generic intent builder:
IntentBuilder<Extra> builder = AA.getBuilder(SomeActivity.class, Extra.class);It is just an idea, so, tell me if I'm missing something.
Don't forget we have to keep retro-compatibility with AA < 3.1
So we're not going to drop the inner intent builder in generated classes. At least, not now.That being said, in your suggested solution you're still using
IntentBuilder<Extra>which is a generated inner-class. With this, you're not using the generated class but the generated inner-class. Not what we're looking for :)I'll try to find a solution this week, but I'm afraid there is no elegant solution. Right now, I only thinking of using one generated class (the factory) or using reflection in the factory.
Hey, I'm not suggesting to drop compatibility :) Just to add a new way for creating intents, without removing the old one.
AndIntentBuilder<Extra>is not supposed to be generated class, it is suppose to be an interface withsetExtramethod.Your solution is way better than what I tried to propose in #431
I love this idea.
And I second the less reflection, the better approach: offering a feature that improves maintainability (and fixes some Eclipse quirks) but impairs performance for the end user is a real dilemma :)6 remaining items
@jeremiemartinez Could you provide us a example of code using your feature?
I built @jeremiemartinez inject branch.
So far, this what I could understand:
- there are two new annotations
@Createsand@Creator - the
@EApplicationhas been modified to take a list of creator - it works only to instantiate EBean
So you create a Creator interface
@ECreator() public interface MyCreator extends Creator { @Creates(MyBean.class) MyBean createMyBean(Context context); }
that you reference in your application
@EApplication(creators = MyCreator.class) public class MyApplication extends Application { }
and then you get to use the
CreatorFacadethat let you create enhanced beans@EActivity public class MyActivity extends Activity { @Bean MyBean aBean; @AfterViews void init() { MyBean bean = CreatorFacade.getBean(MyBean.class, this); if (bean != null) { System.err.println("This is a MyBean_. Yes for real!"); } } }
Note that the old
@Beanwork also and the generated code will use the newCreatorFacadeclass.Here's the complete test project (with generated classes).
The feature is pretty neat, unfortunately it doesn't work for the bulk of my use cases:
- with
EFragment - simple
MyActivity.classtoMyActivity_.classconversion that are used when you open a new activity.
That being said those features can be added :)
- there are two new annotations
Since Dagger now can be used in conjunction with AA, we should provide integratation with it and let Dagger inject our
@EBeans.BTW, this injection thing should be in a separate issue, it has little to do with builder classes.
Tell me if I'm wrong but this issue should be closed now that #994 has been merged. Am I right ?
No. This is about creating one builder class which can create instances of the generated classes, so we do not have to reference generated code. See the OP and initial discussion. BTW #1017 is little bit wants the same. We should clarify the scope of this issue and the other.
Right, but I think this feature will be included in the other PR in order to handle your case 4 (ie: using EBean in non-enhanced classes).
@Artyomcool this is the same as #1017 am i right?
BTW, we could modify the manifest file easily in Gradle and Maven builds by replacing the Activity/Service names with the generated ones. With this and the builder, we cold completely get rid of "_"s. I think that would be cool.
Another idea: we could override
startActivityetc. methods, and use the common builder in that. That way the user just have to callstartActivity(this, new Intent(Annotated.class), andstartActivitywill modify theIntentto use theAnnotated_.class. However in that way the user could not use the generated setter methods for@Extraetc, and requires more boilerplate then the current solution.
This code depends on generated class:
It would be a big problem, if it is the only place. E.g. I want to make my tests independent from AA, or drop AA at all in the future (don't believe that it is possible for me, but still :)).
Maybe it is better to have just one class for constructions like:
Is it possible?