Dagger2 vs Application class in android - android

By this simple example
public class MyApp extends Application {
private static MyApp app;
private ImageDownloaderComponent imageDownloaderComponent; // dagger2
ImageDownloader imageDownloader;
#Override
public void onCreate() {
super.onCreate();
app = this;
imageDownloaderComponent = DaggerImageDownloaderComponent.builder().imageDownloaderModule(new ImageDownloaderModule(this)).build();
imageDownloader=new ImageDownloader(this);
}
public static MyApp app(){
return app;
}
public ImageDownloaderComponent getImageDownloaderComponent(){
return this.imageDownloaderComponent;
}
}
using Dagger2
public class MainActivity extends AppCompatActivity {
#Inject ImageDownloader downloader;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
MyApp.app().getImageDownloaderComponent().inject(this);
ImageView imageView = findViewById(R.id.main_image);
downloader.toImageView(imageView, "https://..../fruits.png");
} }
without dagger2
public class Main2Activity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
ImageView imageView = findViewById(R.id.main_image);
MyApp.app().imageDownloader.toImageView(imageView, "https://---/fruits.png");
}
}
Both the case activity is working fine. my question why we need dagger2 even the same task performed by the application class? how the way its effective? i google it ,i got its easy for testing apart from any benefits there?? which activity is good in above examples? why?

As we know Dagger is Dependency Injection.
Brief which makes the dagger unique:
Benefits:
If we are using dagger in very small projects/tasks like you given then dagger doesn't
deserve for that.It would be more efficient it is used in intermediate,long applications. Because it help us to avoid unwanted object creation in the code.
We can use the dagger to reuse the object through object graph.
We can distribute the dependency like for
Project level
App level
Module level(Like : Home,Account in the app)
We can define custom scope ,also there are some already defined scopes like Singleton , there are good concepts in dagger like component dependency & sub component.
Can inject Class,Object,Constructor.

Related

Difference between void inject(Activity activity) and SomeComponent getSomeComponent()

Usually when using Dagger 2 and android I have the following:
#Singleton
#Component(modules = {ApplicationModule.class})
public interface ApplicationComponent {
void inject(MainActivity activity);
}
public class MainActivity extends Activity {
#Inject SharedPreferences mSharedPrefs;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
((DemoApplication) getApplication())
.getComponent()
.inject(this);
}
}
But recently I have seen this:
#Singleton
#Component(modules = {ApplicationModule.class})
public interface ApplicationComponent {
SharedPreferences getSharedPreferences();
}
public class MainActivity extends Activity {
SharedPreferences mSharedPrefs;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mSharedPrefs = ((DemoApplication) getApplication())
.getComponent().getSharedPreferences();
}
}
I have omitted the DemoApplication class and the Module class, they are standard.
What is the difference between these two approaches? Pro's and con's of either? Maybe a right or wrong way?
The dependency inversion principle of software engineering suggests that we should try and depend on abstractions rather than concretions.
For this reason, you should prefer the #Inject annotations (abstract) for field injection in your Activity rather than calling the provision method from the Dagger Component (concrete).
Why? You will notice that the #Inject annotations are part of the javax.inject package. This is a standard for dependency injection APIs introduced into Java as part of JSR330. There are other DI frameworks, such as Guice and Toothpick, that can use these annotations. If you have to switch DI frameworks in the future it will be easier if you use the #Inject annotations. Yes, it does happen that you have to change DI frameworks. Roboguice is an example of a popular DI framework that has recently been retired.
To illustrate, let's take your Activity, add a few dependencies, and extract a method for injection like this:
public class MainActivity extends Activity {
#Inject SharedPreferences mSharedPrefs;
#Inject Foo foo;
#Inject Bar bar;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#VisibleForTesting
protected void injectMembers() {
((DemoApplication) getApplication())
.getComponent()
.inject(this);
}
}
A wild (new) DI framework appears! You now have to change your app to use it quickly! You use JSR330. It's super-effective! (translation: you can re-use your JSR330 #Inject annotations because the new DI framework supports them). If you had changed to a new Guice-like framework, all you would need to do is rewrite your method:
#VisibleForTesting
protected void injectMembers() {
GuiceLikeInjector.getInjector(this).injectMembers();
}
In contrast, if you had injected those fields manually using .getSharedPreferences(), getFoo() it's not very effective - you have to change a lot of lines of code.
If you look at the generated code of the Component, you'll notice that it implements the inject(MainActivity) method by setting injected fields directly using the activity reference you're passing it.
So both options do the same thing.
I prefer the first approach for 2 main reasons. First it is a lot clearer that fields are injected when they are annotated as such, and second it keeps the code much cleaner. In the example you gave you inject a single field and it's harder to see the benefit, but I think it becomes much more apparent when you need to inject 10 fields, where you will have to assign all of them in the onCreate(), and declare getters for them in the component.

Dagger 2 - How does marking a class constructor with #Inject without component registration work

i have dagger already set up with two components. One component is a subcomponent of another, big deal. Everything works. But then i randomly wanted to try constructor injection so i created a random class and marked its constructor with the Inject annotation and to my surprise when i wnated to inject this class it works ? my Component(s) know nothing about this. I have no written in my components interface about this class. its just a random class that has a constructor annotated with #Inject. How is this working ? Here is the random class:
public class Knife {
#Inject
public Knife(){
System.out.println("a spreading knife has been created");
};
}
and here is how call inject my class if that matters:
public class MainActivity extends AppCompatActivity {
private final String TAG = getClass().getSimpleName();
//#Inject
//AlmondButter someAlmondButter;
#Inject
CashewSandwich sandwich;
#Inject
CashewSandwich sandwich2;
/*some how this is getting injected but its not in any component, how ?No ones
providing it in a module either*/
#Inject
Knife mKnife;
SandwichComponent sandwichComponent;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
/*create the dependent butter for the sandwich here*/
ButterComponent butterComponent=DaggerButterComponent.builder().
butterModule(new ButterModule()).build();
/*create a scope sandwichcomponent here */
sandwichComponent=DaggerSandwichComponent.builder().sandwichModule(new SandwichModule()).
butterComponent(butterComponent)
.build();
//finally we have a sandwichComponent, lets inject our dependencies
sandwichComponent.inject(this);
Log.v(TAG," first:"+sandwich.toString());
Log.v(TAG,"second:"+sandwich2.toString());
Log.v(TAG,mKnife.toString()); //this actually works !
}
}
UPDATE: I wrote a blog on this feature incase anyone needs help:
http://j2emanue.blogspot.ca/
Placing #Inject on a constructor makes it detectable to Dagger. You can read more about it in JSR 330.

Dagger 2: injecting singleton with lots of access points

I just started with DI / Dagger 2. I have a huge project. To try dagger 2, I started with injecting my singleton class 'MyPreferences'. This class handles all app actions from and to the SharedPreferences.
Auto-injecting the SharedPreferences in the MyPreferences went perfectly.
However, I am using this singleton in about 50 classes, I used to do this:
MyPreferences.getInstance(context).getXXXSetting();
I have changed this to dagger2 injection in a few classes, and it works fine, but I find myself copying these lines all the time:
#Inject
protected MyPreferences myPreferences;
protected void initInjection(Context context) {
((RootApplicationDi) context.getApplicationContext()).getComponent().injectTo(this);
}
// + call initInjection # onCreate / constructor
For such a simple call I need all these lines in about 35-40 (super) classes. Am I missing something? Is this really the way to go?
My previous answer was for Dagger 1 and thus incorrect. Here is example solution for Dagger 2:
In your application class:
private MyDagger2Component mDependencyInjector;
#Override
public void onCreate() {
super.onCreate();
mDependencyInjector = DaggerMyDagger2Component.builder()...build();
}
public MyDagger2Component getDependencyInjector() {
return mDependencyInjector;
}
In your base Activity class which your activities extend:
protected MyDaggerComponent getDependencyInjector() {
return ((MyApplication) getApplication()).getDependencyInjector();
}
And in your activity you can now have just one line for the injection:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getDependencyInjector().inject(this);
...
}

Global error handling in Android application with Roboguice

I'm working on a Android app which uses the Roboguice dependency injection framework.
So most of the time we extend RoboActivity, RoboListActivity and similar.
Now I would like to introduce some sort of global error handling which will show some alert or a error activity in case the application crashes.
I have done this before by implementing a base activity like this:
public class BaseActivity extends Activity
{
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
Thread.setDefaultUncaughtExceptionHandler(new GeneralError(this));
}
where I define the default exception handler and all other activities then derived from this one.
Now I'm wondering how this is achieved with Roboguice?
Here is some rough psuedo code that should get you started. It uses the roboguice events to make some of these cross cutting concerns a little easier.
public class GlobalErrorHandler {
// injects the current activity here
#Inject Context context;
public void onCreate(#Observes OnCreateEvent e) {
// Wires up the error handling
Thread.setDefaultUncaughtExceptionHandler(new GeneralError(context));
}
}
public class MySpecificActivity {
// required in every activity that needs error handling
#Inject GlobalErrorHandler errorHandler;
}

Activity interceptor

Is there any way in android to intercept activity method calls (just the standart ones, like "onStart. onCreate")?
I have a lot of functionality that must be present in every activity in my app, and (since it uses different types of activities (List, Preferences)) the only way to do it is to create my custom extensions for every activity class, which sucks :(
P.S. I use roboguice, but since Dalvik doesn't support code generation at runtime, I guess it doesn't help much.
P.S.S. I thought about using AspectJ, but it's too much of a hassle since it requires a lot of complications (ant's build.xml and all that junk)
The roboguice 1.1.1 release includes some basic event support for components injected into a context. See http://code.google.com/p/roboguice/wiki/Events for more info.
For Example:
#ContextScoped
public class MyObserver {
void handleOnCreate(#Observes OnCreatedEvent e) {
Log.i("MyTag", "onCreated");
}
}
public class MyActivity extends RoboActivity {
#Inject MyObserver observer; // injecting the component here will cause auto-wiring of the handleOnCreate method in the component.
protected void onCreate(Bundle state) {
super.onCreate(state); /* observer.handleOnCreate() will be invoked here */
}
}
You could delegate all the repetitive work to another class that would be embedded in your other activities. This way you limit the repetitive work to creating this object and calling its onCreate, onDestroy methods.
class MyActivityDelegate {
MyActivityDelegate(Activity a) {}
public void onCreate(Bundle savedInstanceState) {}
public void onDestroy() {}
}
class MyActivity extends ListActivity {
MyActivityDelegate commonStuff;
public MyActivity() {
commonStuff = MyActivityDelegate(this);
}
public onCreate(Bundle savedInstanceState) {
commonStuff.onCreate(savedInstanceState);
// ...
}
}
This minimalises the hassle and factorises all common methods and members of your activities. The other way to do it is to subclasse all the API's XXXActivty classes :(
Take a look at http://code.google.com/p/android-method-interceptor/, it uses Java Proxies.

Categories

Resources