Skip to content
This repository was archived by the owner on Feb 26, 2023. It is now read-only.
This repository was archived by the owner on Feb 26, 2023. It is now read-only.

Introducing Scopes #352

Description

@pyricau

This issue relates to #331, #205, #207 and probably a few others

AndroidAnnotations' current injection model works fine, but it has some drawbacks:

  • You can't inject the same bean instance multiple times unless you make it a singleton (which is not always desirable)
  • You can't inject fragment views in a fragment dependency (@EBean)
  • You are not guaranteed that @RootContext and view injection / binding will work fine in beans, if a parent bean in the object graph is a singleton. Worst then that, it doesn't fail early, it just skips the injection.

I think this comes from the fact that AndroidAnnotations doesn't have any hierarchy of scopes. The basic idea with scopes is that a child scope may access beans from a parent scope, but not the contrary.

I hacked around this idea and came up with a proof of concept: https://github.com/pyricau/androidannotations-scoping . This is a simple eclipse project that doesn't have any dependency on Android / AA, is just simulates the expected behavior.

From a user point of view, here is what the changes would look like :

  • We would remove the @RootContext, @App and @Bean annotations, and replace them all with an @Inject annotation.
  • @EBean would take an optional value parameter that would correspond to the scope of this bean. When set, this beans is visible within the whole corresponding scope. For instance, if an A has a dependency on B and C, B and C have a dependency on D, and D is in A scope (@EBean(A.class)), then the same D would be injected in both.
  • The most used scope will probably be Activity, but in fact it can be any class, to fit the user needs.

This change will also need to take the specific combination of @NonConfigurationInstance and @Bean into account, and maybe find a new way to reproduce this feature (basically being able to keep bean instances on activity configuration changes).

Also note that this change will break backward compatibility quite much. So I think that would be a good opportunity to do other hard changes, such as renaming the packages from com.googlecode.androidannotations (we're on GitHub now!) to org.androidannotations, change the maven packages, and introduce AndroidAnnotations 3.0.

Activity

  1. pyricau commented on Oct 24, 2012

    @pyricau
    ContributorAuthor

    Special thanks to @ericbottard for listening to my stupid ideas (Rubber duck programming...) and providing a lot of feedback.

  2. pyricau commented on Oct 24, 2012

    @pyricau
    ContributorAuthor

    One question I haven't answered yet is whether we should use JSR-330 @Inject or a custom one.

    Pros :

    • More standard

    Cons :

    • Requires an extra dependency
    • May not play well if integrating with RoboGuice or Dagger
  3. pepyakin commented on Oct 24, 2012

    @pepyakin

    Extra dependency and intergration woe for only one annotation?
    I think would be better to create annotation with diffrent name than @Inject, for example @Wired.

  4. pyricau commented on Oct 24, 2012

    @pyricau
    ContributorAuthor

    @pepyakin interesting. Makes me think of Spring @Autowired. I was also thinking about using @Inject with a different package, but then mixing both would need using qualified names.

  5. ericbottard commented on Oct 24, 2012

    @ericbottard

    Thanks for portraying me as a duck. I would refrain from using @Inject in a different package, as this would bring much confusion.

  6. pepyakin commented on Oct 24, 2012

    @pepyakin

    @pyricau yep, i kept Spring in mind while thought about @Wired. But I made it not @Auto... for avoid collision with spring.

    I think @Inject in diffrent package might be little bit confusing. For example, if you using auto-complete feature, you can mistakingly import JSR-330 version of @Inject and have unexpected NullPointerException.

  7. johncarl81 commented on Oct 24, 2012

    @johncarl81
    Contributor

    Kind of curious @pyricau , what scopes are you planning?

  8. pyricau commented on Oct 25, 2012

    @pyricau
    ContributorAuthor

    @johncarl81 The basic idea here is that we do not create predefined scopes. Any scope is valid: each new node in the dependency graph is a new scope. This means the injection process will create a defacto scope tree. Then, inside the dependency graph, you're able to attach @EBean to a scope from a parent node, which gives it broader visibility.

    We'll document how to use scope for singletons, activities, fragments... and then anyone could make its own if needed.

    Just to be clear, I'm not talking about scopes in the exact sense of Spring or Guice scopes, but more like Module / Container hierarchies. It's an injection time scope.

    By the way, I like @Wired.

  9. johncarl81 commented on Oct 25, 2012

    @johncarl81
    Contributor

    @pyricau Makes sense... I should have read your initial proposal more closely before commenting ;-)

  10. pyricau commented on Nov 3, 2012

    @pyricau
    ContributorAuthor

    @RestService (rest service injection) should also be replaced by @Wired.

  11. pepyakin commented on Nov 3, 2012

    @pepyakin

    I think it will be better if @Afterviews also 'll be renamed.

  12. pyricau commented on Nov 4, 2012

    @pyricau
    ContributorAuthor

    Hum.. That's kind of unrelated. What name would use suggest instead of @AfterViews ?

  13. pepyakin commented on Nov 4, 2012

    @pepyakin

    Yep, maybe. Just was sleeping when tought about it. As I can see @Afterviews means that the marked method will execute "after views" has been injected. Because it is possible to inject not only views now, it is makes annotation name little bit confusing.

  14. pyricau commented on Nov 5, 2012

    @pyricau
    ContributorAuthor

    Oh, I see. Well, in fact, we already have a @AfterInject annotation :) . Basically, here is what happens:

    • onCreate() is called on the activity subclass.
    • We inject everything that's not views
    • We then call any @AfterInject method
    • Then we call super.onCreate().
    • Then we "may" call setContentView() if a layout is set.

    Furthermore, we override setContentView() to inject views immediately after the content view is set. And after injecting those views and binding the listeners, we call @AfterViews methods.

    This means that any time you call setContentView() from within your code, view injection will happen again.

  15. pyricau commented on Nov 25, 2012

    @pyricau
    ContributorAuthor

    I'm not sure yet about the whole scope thing. One thing that's still interesting though is the ability to inject fragments, activities, applications etc with the same @Wired annotation. The type of the injected element provides enough information (basically its @EXXX annotation) to be able to determine what to do.

  16. pyricau commented on Feb 27, 2013

    @pyricau
    ContributorAuthor

    I gave it a bit more time, and realized this whole thing is quite an over-engineering :) . Let's keep it simple.
    I will close this issue, and create new issues for some of the ideas I like in there.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions