Asked to inject parent class when no injections take place there - android

I'm experimenting with Dagger and trying to get an ObjectGraph set up. I created a BaseModule that houses stuff like my SharedPreferences and Bus. I created a WidgetModule that contains things such as Picasso for image loading.
I'm trying to inject Picasso into one of my adapter classes. In the adapter constructor I get my ObjectGraph instance and then inject the adapter. I get a runtime exception complaining:
Caused by: java.lang.IllegalArgumentException: No inject registered for members/<ParentClass>$1. You must explicitly add it to the 'injects' option in one of your modules.
This is odd to me because I don't perform any injections in that class. ParentClass is where I create my adapter, but the injection happens in the adapter itself. Do I really need to declare the parent class that has no injections into my injects annotation? Here is my adapter constructor:
public MyAdapter(Context context, int textViewResourceId, List<Item> items) {
super(context, textViewResourceId, items);
MyApplication.get(getContext()).inject(this); //exception occurs here
}
Here are my modules:
#Module(
injects = {
MyApplication.class,
}
)
public final class BaseModule {
//...
}
#Module(
injects = MyAdapter.class
)
public class WidgetModule {
public WidgetModule(Application app) {
this.app = app;
}
#Provides
#Singleton
Picasso providePicasso() {
return new Picasso.Builder(app)
.build();
}
}
As you can see I have my adapter class in my injects, so why is it mentioning the parent class at all?
Also, is this the proper structure for creating an ObjectGraph? The documentation on includes and addsTo is very sparse and all of the demo projects like U2020 are ambiguous to what they actually mean. I'm trying to separate the Modules so that I can override them easily if I need to.
edit: It turns out that I get the exception even if I add the parent class to both modules. This is bizarre.

I ended up fixing this. For some reason Dagger just couldn't inject my adapter. What I did was inject Picasso into the adapter's parent (my custom View) and then pass it to my adapter via its constructor. Not sure why this works as opposed to injecting in my adapter directly because now I have a useless Picasso field in my View class. I'm still open to other answers that provide a better solution, but this works for now.

Use
((MyApplication) context.getApplicationContext()).inject(this);
instead of
MyApplication.get(getContext()).inject(this);
and add
public void inject(Object object) { graph.inject(object); }
in MyApplication as seen in Dagger samples.

Related

Android - keep webservice results in memory

In my Android app I have to query some user/session dependent data from a rest webservice. Now I need a way to keep the received webservice results in memory, so that serveral activities/fragments can access them.
I don't want to persist the data (for example a list of the users bank accounts) into a database on the device, because the data expires after a while or when the user logs out.
I also don't want to request the data again and again from webservice, when the user navigates to another activity.
Are there any approved patterns to keep a set of data (some pojo's with more or less properties) in memory during the application is running?
Just for info: I'm experimenting with dagger2, mvp, retrofit2, rxandroid
Regards
Martin
If you already experimenting with Dagger 2, then all you need to do is instantiate a component in Application and use this component in your Activities and Fragments in order to inject a scoped "service".
For example:
Create a class named XyzManager (where Xyz = the actual functionality this manager is responsible for)
Annotate its #Provides method (in Dagger's module) with #Singleton scope
Make sure that the component that injects XyzManager instantiated in Application and add getComponent() method to your custom Appliaction class
In your Activities and Fragments inject XyzManager while using the same component - ((MyApplication)getApplication()).getComponent().inject(this)
If you take the above steps, then all your Activities and Fragments will get a reference to exactly the same instance of XyzManager, and the data you cache in this manager will be accessible everywhere.
The structure you would get is very similar to the structure described in this answer.
Please note that this approach is much better than resolving to static things (e.g. Singleton pattern, or what #KhalidTaha suggested in his answer).
You might want to take a look at my post concerning Dagger 2 scopes if you need a detailed information on that aspect of the framework.
here is a solution:
1- create a DefaultUtil class:
public calss DefaultUtil{
private List<User> listOfUsers;
public static DefaultUtil getInstance(){
if(instance == null)
{
instance = new DefaultUtil();
}
return instance;
}
public List<User> getUserList(){ return listOfUsers; }
public void setUserList(List<User> userList) {
this.listOfUsers = userList ;
}
}
2- when you finish the webservice, call this code:
DefaultUtil.getInstance().setUserList(myWebserviceListOfUsersResult);
and then you can access the list of users from any class by this:
DefaultUtil.getInstance().getUserList();
#Vasiliy
I've studied the linked answer, but I don't get it. I don't use my BankingSession singleton in an activity directly, so calling "getComponent().inject(this).... " won't work. I use the singleton in other service classes (not Android services... just business logic).
// this should be a single instance across the whole app
#Singleton
public class BankingSession {
#Inject
public BankingSession() {
}
}
public class SessionServiceImpl implements SessionService {
private final BankingSession bankingSession;
#Inject
public SessionServiceImpl(BankingSession bankingSession) {
this.bankingSession = bankingSession;
}
}
#Module
public class SessionModule {
#Provides
public SessionService provideSessionService(SessionServiceImpl sessionService) {
return sessionService;
}
}
#Singleton
#Component(modules = {AppModule.class, NetworkModule.class, SessionModule.class})
public interface AppComponent {
Application application();
LoginComponent plus(LoginModule module);
AccountComponent plus(AccountModule module);
BankingSession bankingSession();
}
No matter how I try it, the constructor of BankingSession get's called multiple times

Dagger2 Inject a lot of activities/fragments/services (possible get a lot of NPE)

We used RoboGuice, but it's deprecated I start replace it with Dagger2.
// https://github.com/google/dagger
compile('com.google.dagger:dagger:2.7')
annotationProcessor 'com.google.dagger:dagger-compiler:2.7'
provided 'org.glassfish:javax.annotation:10.0-b28'
#Module
public class ApplicationModule {
Application mApp;
public ApplicationModule(#NonNull Application app) {
Preconditions.checkNotNull(app);
mApp = app;
}
#Provides
#Singleton
public SharedPreferences providesSharedPrefs() {
return PreferenceManager.getDefaultSharedPreferences(mApp);
}
#Provides
#Singleton
public DateHelper providesDateHelper() {
return new DateHelper(mApp);
}
#Provides
#Singleton
public PersistentConfig providesPersistentConfig() {
return new PersistentConfig(mApp);
}
#Provides
#Singleton
public OttoBus providesOttoBus() {
return new OttoBus();
}
}
public class Application extends MultiDexApplication {
private ApplicationComponent mApplicationComponent;
#Override
public void onCreate() {
super.onCreate();
mApplicationComponent = DaggerApplicationComponent.builder()
.applicationModule(new ApplicationModule(this))
.build();
mApplicationComponent.inject(this);
}
public static Application getApp(#NonNull Context context) {
return (Application) context.getApplicationContext();
}
public static ApplicationComponent getApplicationComponent(#NonNull Context context) {
return getApp(context).getApplicationComponent();
}
}
And after everywhere when I want to inject ApplicationComponent
For example MainActivity
public class MainActivity extends AppCompatActivity {
#Inject
PersistentConfig mPersistentConfig;
#Inject
OttoBus mOttoBus;
#Override
public void onCreate(Bundle savedInstanceState) {
Helper.manageRotation(this);
super.onCreate(null);
setContentView(R.layout.main_layout);
Application.getApplicationComponent(this).inject(this);
}
}
Application.getApplicationComponent(context).inject(this);
First question: I'm really confused about interface ApplicationComponent which must provide all activities/fragments/services (etc) where I want to use injection. But I can't use generic objects like Activity / Fragment. Or am I really out of reality and don't understand how Dagger2 works?
Because this is really crazy for project with about 50+ activities and a tons of fragments/services...
#Singleton
#Component(modules = {ApplicationModule.class})
public interface ApplicationComponent {
void inject(#NonNull Application app);
void inject(#NonNull MainActivity object);
void inject(#NonNull DispatcherActivity object);
void inject(#NonNull DateTimeHelper object);
void inject(#NonNull DatabaseHelper object);
void inject(#NonNull LandingPageActivityFragment object);
void inject(#NonNull RedirectActivity object);
void inject(#NonNull CategoryFragment object);
void inject(#NonNull BaseModuleFragment object);
void inject(#NonNull NotificationHelper object);
void inject(#NonNull RecordAdapter object);
void inject(#NonNull PagingProvider object);
void inject(#NonNull FilterDialog object);
... next 100+ injections?
}
Said me, that it can't be real...
Second question: How I can provide to inject generic classes, when I can't use it like void inject(#NonNull NotificationHelper<? extends GenericObject> object); because it require specific object. So I must write all this objects inside ApplicationComponent and not use ? notation?
It's a much more than just crazy :(. Maybe better stay with RoboGuice which is much more developer friendly and don't need make this overhead and manual check every injected objects? When I forgot add them to this list, I will get NPE in runtime (when I will not test it a lot it will crash customers).
It's much faster write it manually, than make a list of all object when it's not possible to use generic objects like Activity / Fragment / Service.
Is there a better solution, when I don't want use same generic BaseActivity which will inject every part of ApplicationModule and every activity will be extended by this huge BaseActivity?
This question has aspects of a complaint, but to attempt an answer:
I'm really confused about interface ApplicationComponent which must provide all activities/fragments/services (etc) where I want to use injection. But I can't use generic objects like Activity / Fragment. Or am I really out of reality and don't understand how Dagger2 works?
This is, indeed, how Dagger 2 works; it you must statically supply the type of the injection target inside the injector (component) and you cannot use 'generic' (covariant) types. Dagger 2 does this in order to maintain a DI framework that is 100% static.
Note that you are specifying RecordAdapter and DatabaseHelper as injection sites. You probably don't need to do that, you should try and only specify top level objects for which the constructor is not visible (Activity, Fragment, and Service) as injection sites. The rest of the objects should be able to be constructed through annotating their dependencies with #Inject and specifying their dependencies, if any, in a Module.
Maybe better stay with RoboGuice which is much more developer friendly and don't need make this overhead and manual check every injected objects
Yes Roboguice is more friendly in the sense that you don't have to worry about specifying the injection targets. However, consider the following in Roboguice: 1. The 'red stacktrace of death' you get when you set up your object graph incorrectly
2. The fact that you cannot get see which implementations of interfaces are actually being used in your project with Find Usages which can also be 'developer unfriendly'
Is there a better solution, when I don't want use same generic BaseActivity which will inject every part of ApplicationModule and every activity will be extended by this huge BaseActivity?
Well, it would depend which dependencies you are using and where. If you have a small list of dependencies that you want to inject everywhere, that may be the best solution i.e., make a BaseActivity that receives injection of these and makes this available to all of your subclasses. Alternatively, you can use sub-components and modules you can divide up your object graph so that you can group consumers/injection targets together with the correct modules. Then you don't need to have one 'god' component that lists all of the injection sites.
Second question: How I can provide to inject generic classes, when I can't use it like void inject(#NonNull NotificationHelper object); because it require specific object. So I must write all this objects inside ApplicationComponent and not use ? notation?
Yes, you must supply the invariant type of the injection target. I am not sure if your NotificationHelper<String> is a top level type. Why not inject it through the object graph when you inject in a Fragment, Activity or Service?
If it absolutely must be an injection target you will need to subclass: NotificationHelper<String> and Notification<Integer> become StringNotificationHelper extends NotificationHelper<String>, IntegerNotficationHelper extends NotificationHelper<Integer>. This is a practice recommended in the book Clean Code.
You don't need to write it all the injection sites inside the ApplicationComponent, you may create subcomponents that correspond with the consumption patterns of the dependencies in your project.
(disclosure: as someone who is currently trying to migrate a project from Roboguice to Dagger 2 I am sympathetic to your complaint)
Thanks, we solved it as you described a week ago. Using every objects as injected.
Better solution for it is don't use only inject but complex name. Why? Because it will help to resolve why some object is not injected (you know, base classes and so on).
#Singleton
#Component(modules = {ApplicationModule.class})
public interface ApplicationComponent {
void injectApplication(#NonNull Application app);
void injectMainActivity(#NonNull MainActivity object);
void injectDispatcherActivity(#NonNull DispatcherActivity object);
...
}
We finally use for genericity UtilityWrapper as is described here: https://medium.com/#patrykpoborca/dagger-2-and-base-classes-generics-and-presenter-injection-7d82053080c#.b58ykd4cm

Android Dagger 2: Inject versus Provides

I have a question regarding Android Dagger 2 und the usage of #Inject and #Provide annotations. Given are the following two simplified examples:
public class A {
String msg;
public A(String msg){
this.msg = msg;
}
}
public class B {
public A a;
public B(A a){
this.a = a;
}
}
#Module
public class AModule {
#Provides
A providesA(){
return new A("blah");
}
#Provides
B ProvidesB(A a)
{
return new B(a);
}
}
The example is pretty straight forward, I have two methods in my AModule with #Provides annotations. Therefore, Dagger can create an object of B using an instance of A with the string blah.
My second example looks like this:
public class A {
String msg;
public A(String msg){
this.msg = msg;
}
}
public class B {
public A a;
#Inject
public B(A a){
this.a = a;
}
}
#Module
public class AModule {
#Provides
A providesA(){
return new A("blah");
}
}
In this example, Dagger can create an instance of B because an object A can be created using AModule. The instance of B can be created because it's constructor uses the #Inject annotation.
So my question is: What's the difference between those two examples? Both seem to have the same semantics. Does the generated code differ and are there any pitfalls? Or is it just a matter or personal taste or best practices?
They work similarly, and the #Inject style is preferred when you have such an easy choice like in your example. However, this isn't always the case:
If B, which consumes A, is not under your control and not DI-aware, you will have no way to add the #Inject annotation.
If B is an interface, you will need #Provides (or #Binds in newer Dagger versions) to identify which implementation to use.
If you choose not to use your Dagger object graph for every injected parameter, you can call the constructor manually whether it is marked #Inject or not. This might be the case if you want a specific instance or constant as a constructor parameter, but you can't or don't want to set up the binding for the whole object graph.
#Provides allows you to effectively create a factory method, with everything that allows. This is a great way to change which instances are included in your graph, or to effectively add to the class's constructor graph-wide if you can't (or shouldn't) change the class itself.
You can return an existing instance rather than a new one. Note that custom scopes (implemented in Dagger through subcomponents) might be a better fit for common cases, but if you have more complex instance control or use a third-party library that controls instances, you could put that into your factory method.
If you want your binding to return null sometimes that logic can live in a #Provides method. Make sure you annotate the injection sites as #Nullable.
You can choose between implementations with a factory method like a #Provides method, particularly if the choice depends on runtime environment.
You can run post-construction logic, including instance registration or initialization.

What is the best way to inject subclasses using Dagger 2?

I recently started using Dagger 2 to manage the depency injections of my app. In order to make some classes testable, I started creating many classes that I need to inject. I was able to do so, however, the process to get these new classes injected look a little bit complicaded to me. Lets take an example:
I would like to test, for instance, the method onCreateViewHolder() from my RecyclerViewAdapter. To do so, I've created a Factory that returns the ViewHolder based on the given LayoutType:
public class ViewHolderFactor {
public RecyclerView.ViewHolder getViewHolder(ViewGroup parent, int viewType) {
LayoutInflater inflater = this.getLayoutInflater(parent.getContext());
View view;
switch (LayoutType.fromInteger(viewType)) {
case SMALL_VERTICAL:
view = inflater.inflate(R.layout.rsc_util_item_small, parent, false);
return new ViewHolder.ItemViewHolder(view);
case LARGE_VERTICAL:
view = inflater.inflate(R.layout.rsc_util_item_large, parent, false);
return new ViewHolder.ItemViewHolder(view);
}
return null;
}
private LayoutInflater getLayoutInflater(Context context) {
return LayoutInflater.from(context);
}
}
By moving the above code to a separated class, I'm able to perform my unit test using:
#RunWith(JUnit4.class)
public class TestViewHolderFactor extends TestCase {
ViewHolderFactor viewHolderFactor;
#Test
public void testGetViewHolder () {
this.viewHolderFactor = Mockito.mock(ViewHolderFactor.class);
ViewGroup viewGroup = Mockito.mock(ViewGroup.class);
Mockito.when(viewHolderFactor.getViewHolder(viewGroup, LayoutType.SMALL_VERTICAL.toInteger())).thenCallRealMethod();
Context context = Mockito.mock(Context.class);
Mockito.when(viewGroup.getContext()).thenReturn(context);
LayoutInflater layoutInflater = Mockito.mock(LayoutInflater.class);
Mockito.when(viewHolderFactor.getLayoutInflater(context)).thenReturn(layoutInflater);
Mockito.when(layoutInflater.inflate(R.layout.rsc_util_item_small, viewGroup, false)).thenReturn(Mockito.mock(View.class));
RecyclerView.ViewHolder result = viewHolderFactor.getViewHolder(viewGroup, LayoutType.SMALL_VERTICAL.toInteger());
assertNotNull(result);
}
}
Problem is: now, to make the app work, I will also have to inject the outter class that holds an instance to the factor (something that I wasn't doing before creating ViewHolderFactor). At end, I will have a Dagger configuration like that:
#Module
public class ModuleBusiness {
#Provides
public CharacterUIService provideCharacterService(Picasso picasso, NotificationUtil notificationUtil, ViewHolderFactor viewHolderFactor) {
return new CharacterUIService(picasso, notificationUtil, viewHolderFactor);
}
}
Where CharacterUIService is the class that creates a new instance of the RecyclerViewAdapter that contains the ViewHolderFactory.
public class
private ViewHolderFactor
#Inject
public CharacterUIService(ViewHolderFactor viewHolderFactor) {
this.mViewHolderFactor = viewHolderFactor;
}
// ...
}
I need a member from ViewHolderFactor in order to inject it.
My worries regards the need to create new global variables and inscrease the number of parameters being passed in the constructor. Is there a better way to inject these subclasses or can I consider it as a good practice in order to allow Unit Tests?
can I consider it as a good practice in order to allow Unit Tests?
First of all—in my personal opinion—I think that you are overdoing the testing. In the test case that you provided you are basically testing the android framework itself. If you want to test the factory, you should test whether a small or large item is returned, rather than the view being not null.
But yes, yours seems like a reasonable approach to allow for unit testing.
Where CharacterUIService is the class that creates a new instance of the RecyclerViewAdapter
You might want to overthink the role of CharacterUIService. "that creates a new instance" sounds like something that should rather be handled by dagger, since you are already using it.
will also have to inject the outter class that holds an instance to the factory
Why? ViewHolderFactor(sic!) has no dependencies itself. And even if it did, what is stopping you from just creating and injecting it with dagger?
class ViewHolderFactor {
#Inject
ViewHolderFactor() { // allow for constructor injection
}
}
class YourAdapter {
ViewHolderFactor mFactor;
#Inject // allow for constructor injection
YourAdapter (ViewHolderFactor factor) {/**/}
}
// now dagger knows how to create that adapter
And just create let dagger create that adapter?
And generally, if you support constructor injection, then you can remove your #Provides providesSomething() methods. Just remove the whole method. You have an #Inject annotation on the constructor, so make use of that and let dagger write that code for you.
// CharacterUIService can be constructor injected.
#Provides // DAGGER WILL DO THIS FOR YOU
public CharacterUIService provideCharacterService(Picasso picasso, NotificationUtil notificationUtil, ViewHolderFactor viewHolderFactor) {
// REMOVE ALL OF THIS.
return new CharacterUIService(picasso, notificationUtil, viewHolderFactor);
}
So while I think you do a good job by making things testable, you should have again a good look on dagger, since you are obviously mixing many things up. Have a good look on constructor injection and make use of it, it saves you a whole lot of work.

How can I inject parameter through constructor in Roboguice? [android]

This question is probably exact duplicate of this one
Pass parameter to constructor with Guice
Difference is that I use roboguice for android, not just Guice, so answers there does not work for me.
Question is - how can I pass initialize parameters into created object? I.e. I have injected interface which should be initialize with some parameter which roboguice does not know.
What I see in link I provide, I should create factory interface and register it like this
void configure(Binder binder) {
binder.install(new FactoryModuleBuilder()
.implement(FooInterface.class, Foo.class)
.build(FooFactory.class));
}
But I can't find FactoryModuleBuilder class. I use Intellij IDEA, it can show me every class which I can access at current place and I can be 100% sure that there is no classes which starts with 'Factory' word.
How can I create my factory using roboguice?
UPDATED
I forgot to download guice-assistedinject. But still I can't figure out where should I register this factory.
UPDATE 2
Why I need that? Because there should be situation where some abstraction has dependency which could not be resolved by Roboguice. This dependency could be any type, even simple string or number.
In my case I have NumberPicker control on UI and I want to move all UI specific tasks in MyNumberPickerWrapper class. And when I create this wrapper I inject its dependency (this control) through constructor.
It's not the point if I am right with such approach, but that there could be a plenty of another more applicable example where constructor injection needed and this injected classes could not be created by Roboguice
I followed the steps of the answer given in Pass parameter to constructor with Guice and did slight modifications to run it under roboguice. Works completely fine for me.
add guice-assistinject library to gradle script
dependencies { compile 'com.google.inject.extensions:guice-assistedinject:4.+' }
Create Factory interface that with create method that accepts parameters the object constructor requires and returns object's interface
public interface ICustomObjectFactory {
ICustomObject create(String queueName);
}
Add #Inject annotation to constructor of the object and #Assisted annotation to each parameter coming from factory.
public class CustomObject implements ICustomObject {
protected String name;
#Inject
public CustomObject(#Assisted String name){
this.name = name;
}
}
Add binding into the Module that you are using
public class SomeModule extends AbstractModule {
#Override
protected void configure() {
install(new FactoryModuleBuilder()
.implement(ICustomObject.class, CustomObject.class)
.build(ICustomObjectFactory.class));
}
}
Inject factory and create instances of your object
public class SomeClass {
#Inject ICustomObjectFactory factory;
public SomeClass () {
ICustomObject first = this.factory.create("first");
ICustomObject second = this.factory.create("second");
}
}
I faced this same problem and I succeed thanks to Pavel's answer. I only have had to struggle with some errors, and I don't know if it's due to the versions of the libraries used, but for me didn't work without modifying the annotation of the constructor, replacing #Inject by #AssistedInject. With that, the code of the class that implements the interface looks like this.
public class CustomObject implements ICustomObject {
protected String name;
#AssistedInject
public CustomObject(#Assisted String name){
this.name = name;
}
}

Categories

Resources