Dagger2 It's difficult. Since the introduction was difficult, I briefly summarized the introduction part for the time being, using various sites as clues. This blog uses @Inject, @Module, @Provide, @Component, I'd like to write as clearly as possible, up to the point of injecting dependencies and switching functions. For some reason, I chose Java this time.
"Compilation framework for dependency injection" developed by google To put it simply, if you create an instance of another class in a class, Since it becomes difficult to test each class, Switch to dependency injection, which is a method of creating an instance at compile time and injecting it. To make it easier to maintain and test.
・ [Official] GitHub https://github.com/google/dagger ・ [Official] User's Guide https://google.github.io/dagger/users-guide.html ・ Introduction to dagger2 (2.11) that is extremely easy to understand ――It's incredibly easy to understand! https://qiita.com/m-dove/items/767c4bfaeee53caefc4d ・ I understand this (I think I understand)! Dagger 2 --The annotations are summarized in an easy-to-understand manner. https://qiita.com/kikuchy/items/a96809d621845dead8d2 ・ In short, what is DI? ――It wasn't Java, but I used this example as a reference. https://nekogata.hatenablog.com/entry/2014/02/13/073043
[\ 1 ] Sample before using Dagger2 [Sample dependent injection using \ 2 ] @Inject, @Component Sample to switch injection contents using @Module, @Provide
This is a simple sample. Create an instance of Fortune Machine with MainActivity. Then, the constructor of FortuneMachine creates an instance of TwiterClient. When you call checkFortune of FortuneMachine, you will get a random fortune. Post to Twitter with postData of TwitterClient. (The Twitter post part is broken, just spit out the log) Just in case, the string is also returned to MainActivity.
MainActivity.java
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
FortuneMachine fortuneMachine = new FortuneMachine();
Log.w( "DEBUG_DATA", "result = " + fortuneMachine.checkFortune());
}
}
FortuneMachine.java
public class FortuneMachine {
TwiterClient twiterClient;
String[] fortunes = {"Daikichi","Nakayoshi","Kokichi","Bad","大Bad"};
public FortuneMachine(){
//Create an instance of TwiterClient
twiterClient = new TwiterClient();
}
public String checkFortune(){
int no = getRandomNo();
twiterClient.postData(fortunes[no]);
return fortunes[no];
}
public int getRandomNo(){
Random r = new Random();
int n = r.nextInt(fortunes.length);
return n;
}
}
TwitterClient.java
public class TwiterClient {
public TwiterClient(){
}
public boolean postData(String fortune){
//Communication processing to Twitter
Log.w("DEBUG_DATA","postData " + fortune);
return true;
}
}
With this program, every time you test Fortune Machine, data will be posted by Twitter Client, and you will be careful when expanding. So let's use Dagger2 to inject the Twitter Client into the Fortune Machine.
[app]build.gradle
implementation "com.google.dagger:dagger:2.11"
implementation "com.google.dagger:dagger-android-support:2.11"
annotationProcessor "com.google.dagger:dagger-android-processor:2.11"
annotationProcessor "com.google.dagger:dagger-compiler:2.11"
MainActivity.java
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//FortuneMachine fortuneMachine = new FortuneMachine();
Machine fortuneMachine = DaggerMainActivity_Machine.create();
String result = fortuneMachine.maker().checkFortune();
Log.w( "DEBUG_DATA", "result = " + result);
}
//Describe the dependent objects in Dagger2
@Component
interface Machine{
FortuneMachine maker();
}
}
FortuneMachine.java
public class FortuneMachine {
//This is the same treatment as New
@Inject
TwiterClient twiterClient;
String[] fortunes = {"Daikichi","Nakayoshi","Kokichi","Bad","大Bad"};
//Also required for the constructor
@Inject
public FortuneMachine(){
// twiterClient = new TwiterClient();
}
public String checkFortune(){
int no = getRandomNo();
twiterClient.postData(fortunes[no]);
return fortunes[no];
}
public int getRandomNo(){
Random r = new Random();
int n = r.nextInt(fortunes.length);
return n;
}
}
TwitterClient.java
public class TwitterClient {
//Also required for the constructor
@Inject
public TwitterClient(){
}
public boolean postData(String fortune){
//Communication processing to Twitter
Log.w("DEBUG_DATA","postData " + fortune);
return true;
}
}
Added settings to build.gradle to use Dagger2.
The part that creates an instance of TwiterClient in FortuneMachine is ------------------------------- @Inject TwiterClient twitter ------------------------------- It has become. The FortuneMachine and TwitterClient constructors also have @Inject.
It is a rule attached to the variable of the instance you want to create by dependency injection and the constructor placed under control. (Complicated rules at this point)
In Main Activity ------------------------------- @Component interface Machine{ FortuneMachine maker(); } ------------------------------- Has been added Instance creation ------------------------------- Machine fortuneMachine = DaggerMainActivity_Machine.create(); ------------------------------- It has changed to.
@Component is a place to put all the dependencies under Dagger2 management. (Comprehensive management?) You can change maker () freely, but you have to remember the format. Once you write this and compile it, DaggerMainActivity_Machine implements MainActivity.Machine A file with the class written will appear. (Details are described in \ [Introduction to dagger2 (2.11) which is very easy to understand] in the reference URL.) You have to remember the rule named Dagger [class name] _ [interface name] that is automatically generated ...
To get that instance, add .create ().
Now, the Twitter Client is not new in Fortune Machine, The externally instantiated one is supposed to be injected into the Fortune Machine.
As you can see by doing so far, there is almost no merit in spite of the troublesomeness! !! However, let's study it because it will be convenient if we develop it from now on: frog:
What I want to do is that you can control what you inject and set whether to upload to Twitter or Facebook without having to mess with Fortune Machine.
To put it briefly at the beginning, I created some Interfaces and implemented them. Let's manage the contents in a class called FortuneModuel and teach it to @Component, who is in general management.
[app]build.gradle
Same as above
MainActivity.java
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//FortuneMachine fortuneMachine = new FortuneMachine();
Machine fortuneMachine;
// fortuneMachine = DaggerMainActivity_Machine.create();
fortuneMachine = DaggerMainActivity_Machine.builder()
.fortuneModule(new FortuneModule())
.build();
String result = fortuneMachine.maker().checkFortune();
Log.w( "DEBUG_DATA", "result = " + result);
}
//Describe the dependent objects in Dagger2
//Describe the module to be used
@Component(modules = FortuneModule.class)
interface Machine{
FortuneMachine maker();
}
}
FortuneMachine.java
public class FortuneMachine {
//This is the same treatment as New
@Inject
Client clinet;
String[] fortunes = {"Daikichi","Nakayoshi","Kokichi","Bad","大Bad"};
//Also required for the constructor
@Inject
public FortuneMachine(){
}
public String checkFortune(){
int no = getRandomNo();
clinet.postData(fortunes[no]);
return fortunes[no];
}
public int getRandomNo(){
Random r = new Random();
int n = r.nextInt(fortunes.length);
return n;
}
}
Client.java
public interface Client {
boolean postData(String fortune);
}
TwitterClient.java
public class TwitterClient implements Client{
//Also required for the constructor
@Inject
public TwitterClient(){
}
public boolean postData(String fortune){
//Communication processing to Twitter
Log.w("DEBUG_DATA","postTwitter " + fortune);
return true;
}
}
FacebookClient.java
public class FacebookClient implements Client {
//Also required for the constructor
@Inject
public FacebookClient(){
}
public boolean postData(String fortune){
//Communication processing to Facebook
Log.w("DEBUG_DATA","postFacebook" + fortune);
return true;
}
}
FortuneModule.java
//Class that provides what is injected
// ...Name it Module
@Module
public class FortuneModule {
//Provide what is injected
// provide...Name it
@Provides
static Client provideClient(){
return new FacebookClient();
}
}
Create a public interface Client. TwitterClient and FacebookClient inherited this, You can define @Inject of FortuneMachine in Clinet and receive the value.
Create a public class Fortune Module. @Provides is attached to the function that manages what is provided to @Inject. @Module is attached to the class that puts @Provides together. In the reference URL \ [I understand this (I think I understand)! Dagger 2 ] ---------------------------------------- If @Inject is a car refueling port, @Module is a gas station and @Provides is a refueling machine installed on the stand. ---------------------------------------- The analogy is excellent.
Module settings have been added to @Component of MainActivity. ---------------------------------------- @Component(modules = FortuneModule.class) ---------------------------------------- Also, the method of creating an instance of DaggerMainActivity_Machine has been changed to the module specified version. ---------------------------------------- fortuneMachine = DaggerMainActivity_Machine.builder() .fortuneModule(new FortuneModule()) .build(); ---------------------------------------- There is a function called fortuneModule casually, but I wonder if it is automatically generated.
Now, just change the value of FoturneModule You can set which Client to use, set Moc, and test.
To be clear, there are too many manners and mystery rules. There is almost no advantage in using this kind of source. You should switch with an if statement as much as switching instances! ?? However, Google's sample source comes with Dagger, so I can't help but understand it ... It seems convenient to use it with ViewModel, so this time.