一、前言:
gitHub 地址:https://github.com/lyyRunning/DaggerAndroid
1. Dagger2的缺點
在使用Dagger2進(jìn)行Android開發(fā)時,不可避免的問題是我們需要實例化一些Android系統(tǒng)的類,比如Activity或者Fragment。最理想的情況是Dagger能夠創(chuàng)建所有需要依賴注入的對象,但事實上,我們不得不在容器的聲明周期中聲明這樣的代碼:
public class FrombulationActivity extends Activity {
@Inject Frombulator frombulator;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// DO THIS FIRST. Otherwise frombulator might be null!
((SomeApplicationBaseType) getContext().getApplicationContext())
.getApplicationComponent()
.newActivityComponentBuilder()
.activity(this)
.build()
.inject(this);
// ... now you can write the exciting code
}
}
這樣的確可以實現(xiàn)Android的依賴注入,但還有兩個問題需要我們?nèi)ッ鎸Γ?/p>
- 類似的復(fù)制性的代碼以后會很難維護(hù)。而且隨著越來越多的開發(fā)者去復(fù)制粘貼這些代碼,很少會有人知道它的作用。
- 更重要的是,它要求注射類型(FrombulationActivity)知道其注射器。 即使這是通過接口而不是具體類型完成的,它打破了依賴注入的核心原則:一個類不應(yīng)該知道如何實現(xiàn)依賴注入。
瑕不掩瑜,雖然Dagger2在Android開發(fā)中有一些問題,但是它強(qiáng)大的功能依然使得開發(fā)人員趨之若鶩,無數(shù)的工程師們嘗試彌補(bǔ)Dagger的這個問題,于是Dagger2-Android,基于Dagger2,應(yīng)用于Android開發(fā),由google開發(fā)的的拓展庫應(yīng)運(yùn)而生。
二、基本使用:
1. 依賴
//一定要添加dagger2的annotationProcessor!
annotationProcessor 'com.google.dagger:dagger-compiler:2.11'
compile 'com.google.dagger:dagger-android:2.11'
//使用支持的類庫
compile 'com.google.dagger:dagger-android-support:2.11'
annotationProcessor 'com.google.dagger:dagger-android-processor:2.11 '
注意:依賴的包單引號一定要成對。
2. 先看看Demo效果
結(jié)構(gòu)如下:
可以看到,我們在MainActivity中需要通過依賴注入,獲得4個對象,同時MainPresenter和MainModel也同樣得到了實例化,我們先看下MVP這個架構(gòu)中三個成員的代碼:
三、詳細(xì)代碼相關(guān):
1. MyApplication 代碼:
我們先聲明我們的Application類,然后記得一定要記得添加到清單文件中:
public class MyApplication extends Application implements HasActivityInjector {
@Inject
DispatchingAndroidInjector<Activity> dispatchingAndroidInjector;
@Override
public void onCreate() {
super.onCreate();
//全局注入
DaggerAppComponent.create().inject(this);
}
@Override
public AndroidInjector<Activity> activityInjector() {
return dispatchingAndroidInjector;
}
}
我們在這里做了幾件事:
- 實現(xiàn)HasActivityInjector接口
- 實現(xiàn)HasActivityInjector接口的activityInjector()方法
- 聲明一個泛型為Activity的DispatchingAndroidInjector成員變量并在activityInjector()方法中返回
注意:我們要先寫AppComponent接口,然后編譯,才能讓編譯器自動生成DaggerAppComponent類。
2. AppComponent 代碼:
/**
* Created by luo on 2019/8/7.
* 全局的快遞員
*/
@Component(modules = {AndroidInjectionModule.class,
AndroidSupportInjectionModule.class,
AppModule.class})
public interface AppComponent {
void inject(MyApplication application);
}
我們在這里做了幾件事:
- 在這個Component中添加了 AndroidInjectionModule 和 AndroidSupportInjectionModule
- 同時添加了MainActivityModule 和 SecondActivityModule的依賴
- 聲明注入方法inject,參數(shù)類型為MyApplication
3. MainACtivity 代碼:
/**
* Created by luo on 2019/8/7.
* 整個 APP 統(tǒng)一的 Moudle,類似大箱子
*
*/
@Module
public abstract class AppModule {
/**
* 引入MainActivityModule
* @return
*/
@ActivityScope
@ContributesAndroidInjector(modules = MainActivityModule.class)
abstract MainActivity contributeMainActivityInject();
/**
* 引入SecondActivityModule
* @return
*/
@ActivityScope
@ContributesAndroidInjector(modules = SecondActivityModule.class)
abstract SecondActivity contributeSecondActivityInject();
}
4. MainACtivity 代碼:
public class MainActivity extends BaseActivity implements MainContract.View {
@Inject
String className;
@Inject
SharedPreferences sp;
@Inject
MainPresenter presenter;
@Inject
Student s1;
@Inject
Student s2;
@BindView(R.id.tv_content)
TextView tvContent;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
tvContent.setText(className + "\n" +
s2.toString() + "\n" +
s1.toString() + "\n" +
sp.toString()
);
}
public void gotoSecond(View view) {
startActivity(new Intent(this, SecondActivity.class));
}
public void requestHttp(View view) {
presenter.requestHttp();
}
/**
* 返回數(shù)據(jù)
*
* @param message
*/
public void onGetMessage(String message) {
Toast.makeText(this, message, Toast.LENGTH_SHORT).show();
}
}
顯然,從結(jié)果來看,我們根本沒有在Activity中添加上文所述的模板代碼:
//就是這些,模板代碼
((SomeApplicationBaseType) getContext().getApplicationContext())
.getApplicationComponent()
.newActivityComponentBuilder()
.activity(this)
.build()
.inject(this);
5. MainContract代碼:
public interface MainContract {
public interface View {
}
public interface Presenter {
}
public interface Model {
}
}
6. MainContract代碼:
public class MainPresenter implements MainContract.Presenter {
private final MainActivity view;
private final MainModel model;
@Inject
public MainPresenter(MainActivity view, MainModel model) {
this.view = view;
this.model = model;
}
public void requestHttp() {
view.onGetMessage(model.returnMessage());
}
}
7. MainModel代碼:
public class MainModel implements MainContract.Model {
@Inject
public MainModel() {
}
public String returnMessage() {
return "小明";
}
}
和Dagger2的使用沒有區(qū)別,其根本原理,都是通過@Inject注解,使Dagger2自動生成對應(yīng)的工廠類,以提供MainPresenter和MainModel的實例。
8. MainActivityModule代碼:
@Module
public class MainActivityModule {
@Provides
static String provideName() {
return MainActivity.class.getName();
}
@Provides
static SharedPreferences provideSp(MainActivity activity) {
return activity.getSharedPreferences("def", Context.MODE_PRIVATE);
}
@Provides
@ActivityScope
static Student provideStudent() {
return new Student();
}
}
9. ActivityScope代碼:
@Scope
@Retention(RUNTIME)
public @interface ActivityScope {
}
10. SecondActivity代碼:
public class SecondActivity extends BaseActivity {
@Inject
String className;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
TextView tv = (TextView) findViewById(R.id.tv_content);
tv.setText(className);
}
}
和MainActivity基本一樣,為了簡便我們只注入了一個String,用來展示類名。
可以看到,我們依然沒有添加冗余的模板代碼,試想,一個app中這樣幾十個Activity容器都不需要這樣的模板代碼,我們的工作量確實減少了很多,同時,也達(dá)到了我們的目的,即:
依賴注入的核心原則:一個類不應(yīng)該知道如何實現(xiàn)依賴注入。
實際上,我們只是在BaseActivity中,添加了這樣一行代碼,就實現(xiàn)了我們想要的效果
11. BaseActivity代碼:
public class BaseActivity extends AppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
//一處聲明,處處依賴注入
AndroidInjection.inject(this);
super.onCreate(savedInstanceState);
}
}
接下來,讓我們看看Dagger2-Android 的Module和Component怎么寫
參考:谷歌官方Demo https://google.github.io/dagger//android.html
12. SecondActivityModule代碼:
/**
* Created by luo on 2019/8/7.
* 對應(yīng)每一個 Activity 的小箱子
*/
@Module
public class SecondActivityModule {
@Provides
static String provideName(){
return SecondActivity.class.getName();
}
}
好的,所有配置全部結(jié)束,我們使用ctrl+F9(Mac:cmd+F9)進(jìn)行編譯,運(yùn)行app,依賴注入成功。
四、總結(jié):
注意:除Activity之外,Dagger-Android還提供了Fragment,BroadCast,Service等其他組件的注入方式,詳情請參照官方網(wǎng)站,本文不贅述。
https://google.github.io/dagger//android.html
簡述如下:
- AppComponent 的module : AllActivity的Module,其負(fù)責(zé)所有ActivityModule實例的管理
- AppComponent 為 AllActivity 的 Module 的 subcomponent,管理了提供各activity所需對象的module
- MainActivityModule 負(fù)責(zé)提供所有對應(yīng)Activity所需要對象實例的提供。
參考作者:卻把清梅嗅
鏈接:http://www.lxweimin.com/p/917bf39cae0d