Dagger2 并不是 Jetpack 中的一员。
既然我们说了 Dagger2 是一个依赖注入框架,那么还是需要了解下,什么是依赖注入,为什么要用依赖注入。
类通常需要引用其他类。例如,Car 类可能需要引用 Engine 类,像 Engine 这种被依赖的类称为依赖项。一个类可以通过三种方式获取依赖项的对象:
类构造其所需的依赖项。例如在 Car 类中创建并初始化自己所需的 Engine 实例
从其他地方抓取。如 Android Context 中的 getSystemService()
以参数形式提供。应用可以在构造一个类时提供这些依赖项,或者将这些依赖项传入需要依赖项的函数,如在创建 Car 对象时将 Engine 对象通过 Car 的构造方法或 setter 方法传入
第三种方式就是依赖注入(DI,Dependency Injection)。使用依赖注入时,一个类不必再自己获取依赖项,而是由外部提供。比如说:
/**
* 代码示例1:
* 在 Car 类内部,由 Car 自己创建依赖项 Engine 的实例
*/
class Car {
private Engine engine = new Engine();
public void start() {
engine.start();
}
}
class MyApp {
public static void main(String[] args) {
Car car = new Car();
car.start();
}
}
按照上述代码,Car 对 Engine 是一个强依赖关系,不利于扩展和测试,在使用依赖注入的方式后:
/**
* 示例代码2:
* 使用依赖注入方式创建对象
*/
class Car {
private final Engine engine;
// 依赖注入方式一:构造方法注入
public Car(Engine engine) {
this.engine = engine;
}
public void start() {
engine.start();
}
// 依赖注入方式二:字段(setter方法)注入
public void setEngine(Engine engine) {
this.engine = engine;
}
}
class MyApp {
public static void main(String[] args) {
// 依赖注入框架实际上干的就是创建对象并交给需要它的类这件事
Engine engine = new Engine();
Car car = new Car(engine);
car.start();
}
}
实现了控制反转(IoC,Inversion of Control),将原本的正向控制,即在 Car 类中主动去获取/创建所需要的外部资源 Engine,改成了被动等待外部获取到一个 Engine 的实例然后注入到 Car 中。这样做的好处有:
重用类以及分离依赖项:更容易换掉依赖项的实现。由于控制反转,代码重用得以改进,并且类不再控制其依赖项的创建方式,而是支持任何配置
易于重构:依赖项在创建对象时或编译时可以进行检查,而不是作为实现详情隐藏
易于测试:类不管理其依赖项,因此在测试时,可以传入不同的实现以测试不同用例
Dagger2 在编译时会自动生成代码,这些生成的代码与原本需要手动编写的注入代码类似,这样就无需我们再手动编写冗长乏味又容易出错的异步代码了。它会完成以下工作:
构建并验证依赖关系图,确保每个对象的依赖关系都能满足且图中不存在依赖循环,简言之就是根据依赖关系生成有向无环图
为有向无环图中的类创建工厂以满足依赖关系,并通过该工厂生产实际对象
通过作用域管理对象的生命周期,并且决定是重复使用依赖项还是创建新的实例
为特定流程创建容器,这样在对象的生命周期结束后,可以及时释放内存中不再需要的对象,提升性能
Dagger2中注解
| 注解 | 描述 |
|---|---|
| @Inject | 指示 Dagger 如何实例化一个对象,可以作用在构造方法或需要注入的字段上 1是在需要依赖的类(下面这样的类都会称为目标类)中标记成员变量告诉Dagger这个类型的变量需要一个实例对象。 2是标记类中的构造方法,告诉Dagger我可以提供这种类型的依赖实例。 |
| @Provides | 指示 Dagger 以非构造方法的方式实例化一个对象 对方法进行注解,都是有返回类型的。用来告诉Dagger我们想如何创建并提供该类型的依赖实例(一般会在方法中new出实例)。用@Provide标记的方法,谷歌推荐采用provide为前缀 |
| @Module | 指示 Dagger 以非构造方法的方式实例化一个对象 @Module这个注解用来标记类(一般类名以Module结尾)。Module主要的作用是用来集中管理@Provide标记的方法。我们定义一个被@Module注解的类,Dagger就会知道在哪里找到依赖来满足创建类的实例。modules的一个重要特征是被设计成区块并可以组合在一起。(例如可以在App中看到多个组合在一起的modules) |
| @Singleton @Scope |
作用域,用来标记依赖项的生命周期(作用域),还有一个作用是标记单例 Dagger2通过自定义注解来限定作用域。这是一个非常强大的功能,所有的对象都不再需要知道怎么管理它自己的实例。Dagger2中有一个默认的作用域注解@Singleton,通常在Android中用来标记在App整个生命周期内存活的实例。也可以自定义一个@PerActivity注解,用来表明生命周期与Activity一致。换句话说,我们可以自定义作用域的粒度(比如@PerFragment, @PerUser等等)。 |
| @Component | 组件,创建一个 Dagger 容器,作为获取依赖项的入口 也可以称为注入器。是@Inject和@Module之间的桥梁,主要职责是把二者组合在一起。@Component注解用来标记接口或者抽象类。所有的components都可以通过它的modules知道它所提供的依赖范围。一个Component可以依赖一个或多个Component,并拿到被依赖Component暴露出来的实例,Component的dependencies属性就是确定依赖关系的实现。 |
| @Subcomponent | 子组件,用来定义更加细致的作用域 |
| @Qualifier | 限定符,当有两个相同的依赖时,它们都继承同一个父类或者均实现同一个接口。当它们被提供给高层时,Component 就不知道我们到底要提供哪一个依赖对象了,因为它找到了两个。@Qualifier不是直接标记在属性上的,而是用来自定义注解的 |
| @Named | @Named是@Qualifier 的一种实现。@Named传递的值只能是字符串 |
public class Watch {
@Inject
public Watch(){
}
public void work(){
ILog.LogDebug("手表工作了");
}
}
@Component
public interface MainActivityComponent {
void inject(MainActivity mainActivity);
}
public class MainActivity extends AppCompatActivity {
@Inject
Watch mWatch;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DaggerMainActivityComponent.builder().build().inject(this);
mWatch.work();
}
}
public class Watch {
//注意这里去掉了@Inject ,改为使用下面provide提供的对象
public Watch(){
}
public void work(){
ILog.LogDebug("手表工作了");
}
}
@Module
public class WatchModule {
@Provides
public Watch provideWatch(){
return new Watch();
}
}
//这里新建了module,用来提供watch实例
@Component(modules = {WatchModule.class)
public interface MainActivityComponent {
void inject(MainActivity mainActivity);
}
public class MainActivity extends AppCompatActivity {
@Inject
Watch mWatch;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DaggerMainActivityComponent.builder().build().inject(this);
mWatch.work();
}
}
public class Man extends People{
public Man(){
}
@Override
public void work() {
ILog.LogDebug("man work");
}
}
public class Woman extends People{
public Woman(){
}
@Override
public void work() {
ILog.LogDebug("woman work");
}
}
@Module
public class PeopleModule {
@Named("man")
@Provides
public People provideMan(){
return new Man();
}
@Named("woman")
@Provides
public People provideWoman(){
return new Woman();
}
}
@Component(modules = {WatchModule.class, PeopleModule.class})
public interface MainActivityComponent {
void inject(MainActivity mainActivity);
}
public class MainActivity extends AppCompatActivity {
@Inject
Watch mWatch;
@Inject
@Named("man")
public People peopleMan;
@Inject
@Named("woman")
public People peopleWoman;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DaggerMainActivityComponent.builder().build().inject(this);
mWatch.work();
peopleWoman.work();
peopleMan.work();
}
}
public class Man extends People{
public Man(){
}
@Override
public void work() {
ILog.LogDebug("man work");
}
}
public class Woman extends People{
public Woman(){
}
@Override
public void work() {
ILog.LogDebug("woman work");
}
}
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
public @interface ManPeople {
}
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
public @interface WomanPeople {
}
@Module
public class PeopleModule {
@ManPeople
@Provides
public People provideMan(){
return new Man();
}
@WomanPeople
@Provides
public People provideWoman(){
return new Woman();
}
}
@Component(modules = {WatchModule.class, PeopleModule.class})
public interface MainActivityComponent {
void inject(MainActivity mainActivity);
}
public class MainActivity extends AppCompatActivity {
@Inject
Watch mWatch;
@Inject
@ManPeople
public People peopleMan;
@Inject
@WomanPeople
public People peopleWoman;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DaggerMainActivityComponent.builder().build().inject(this);
mWatch.work();
peopleWoman.work();
peopleMan.work();
}
}
@Module
public class GsonModule {
@Singleton //使用Singleton修饰,保证在本Activity中多个Gson对象为同一个单例
@Provides
public Gson provideGson(){
return new Gson(); //不使用Singleton修饰,每次都会new一个新的对象
}
}
@Singleton //同样需要标注
@Component(modules = {WatchModule.class, PeopleModule.class, GsonModule.class})
public interface MainActivityComponent {
void inject(MainActivity mainActivity);
void inject(SecondActivity secondActivity);
}
public class MainActivity extends AppCompatActivity {
@Inject
Gson mGson;
@Inject
Gson mGson2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DaggerMainActivityComponent.builder().build().inject(this);
ILog.LogDebug("gons1 hasCode : "+mGson.hashCode()+", gson2 hasCode: "+mGson2.hashCode());
}
}
打印结果:
gons1 hasCode : 76774892, gson2 hasCode: 76774892
Gson 在 MainActivity 中是单例,如果再创建一个 SecondActivity,SecondActivity 创建的Gson 的内存地址和 MainActivity 创建的 Gson 的内存地址是不同的。因为 Gson 只是保证在MainActivityComponent中是单例的,我们创建SecondActivity,就会重新创建一个Component,这样只能保证Gson是局部单例(MainActivity中)
查看@Singleton的源码其实就是用@Scope 标识的注解。为了使 Gson 变为全局单例,我们可以用@Scope 结合Application来实现。当然也可以用@Singleton结合Application来实现,只是用@Scope可以自定义注解名称,这更灵活一些。
@Scope
@Retention(RetentionPolicy.RUNTIME)
public @interface ApplicationScope {
}
@Module
public class GsonModule {
@ApplicationScope
@Provides
public Gson provideGson(){
return new Gson();
}
}
@ApplicationScope
@Component(modules = {GsonModule.class})
public interface MainActivityComponent {
void inject(MainActivity mainActivity);
void inject(SecondActivity secondActivity);
}
public class App extends Application {
MainActivityComponent mainActivityComponent;
@Override
public void onCreate() {
super.onCreate();
mainActivityComponent = DaggerMainActivityComponent.builder().build();
}
public static App get(Context context){
return (App) context.getApplicationContext();
}
public MainActivityComponent getMainActivityComponent(){
return mainActivityComponent;
}
}
public class MainActivity extends AppCompatActivity {
@Inject
Gson mGson;
@Inject
Gson mGson2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
App.get(MainActivity.this).getMainActivityComponent().inject(this);
ILog.LogDebug("gons1 hasCode : "+mGson.hashCode()+", gson2 hasCode: "+mGson2.hashCode());
}
}
public class SecondActivity extends AppCompatActivity {
@Inject
Gson mGson2;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
App.get(SecondActivity.this).getMainActivityComponent().inject(this);
ILog.LogDebug("gson2 hascode: "+mGson2.hashCode());
}
}
MainActivity会打印:
gons1 hasCode : 183205259, gson2 hasCode: 183205259
SecondActivity会打印:
gson2 hascode: 183205259
上面两个activity打印的gson实例 hascode都是一样的,使用的都是全局的component。component中的gson实例肯定也是全局的。
@Component也可以用dependencies依赖于其他Component。
public class SuperMan extends People{
public SuperMan(){
}
@Override
public void work() {
ILog.LogDebug("super man work");
}
}
@Module
public class SuperManModule {
@Provides
public SuperMan provideSuperMan(){
return new SuperMan();
}
}
@Component(modules = SuperManModule.class)
public interface SuperManComponent {
SuperMan getSuperman();
}
@ApplicationScope
@Component(modules = {WatchModule.class, PeopleModule.class},dependencies = SuperManComponent.class)
public interface MainActivityComponent {
void inject(MainActivity mainActivity);
void inject(SecondActivity secondActivity);
}
public class App extends Application {
MainActivityComponent mainActivityComponent;
@Override
public void onCreate() {
super.onCreate();
//注意这里需要传DaggerSuperManComponent实例
mainActivityComponent = DaggerMainActivityComponent.builder().superManComponent(DaggerSuperManComponent.builder().build()).build();
}
public static App get(Context context){
return (App) context.getApplicationContext();
}
public MainActivityComponent getMainActivityComponent(){
return mainActivityComponent;
}
}
public class MainActivity extends AppCompatActivity {
@Inject
SuperMan superMan;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
App.get(MainActivity.this).getMainActivityComponent().inject(this);
superMan.work();
}
}
Dagger2提供了懒加载模式,在@Inject的时候不初始化,而是使用的时候,调用get方法来获取实例。
public class MainActivity extends AppCompatActivity {
@Inject
Lazy<SuperMan> superManLazy;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
App.get(MainActivity.this).getMainActivityComponent().inject(this);
SuperMan superMan = superManLazy.get();
superMan.work();
}
}
✔ 接口方式(@Component) ✔ 手动构建方式(使用 DaggerAppComponent.builder() / factory())
@Singleton
@Component(modules = { AppModule.class, NetworkModule.class })
public interface AppComponent {
void inject(MainActivity activity);
}
编译后 Dagger 自动生成:DaggerAppComponent,你只需要这样创建:
AppComponent appComponent = DaggerAppComponent.create();
📌 create() 有什么特点?
使用 Builder 来创建 Component Step 1:写 Component
@Singleton
@Component(modules = {AppModule.class})
public interface AppComponent {
@Component.Builder
interface Builder {
//作用:把 runtime 对象绑定进依赖图
//Application 不是 Dagger 创建的,它是 Android 创建的,
//所以 Dagger 无法自己 new 一个。
//你必须告诉 Dagger 使用哪个 Application。
//不是必须有的方法,只有当你的依赖图中需要 Application 时才需要。
@BindsInstance
Builder application(Application app);
//作用:让外部传入一个 Module 实例
//为什么?因为你的 Module 有构造参数:
//public class AppModule {
// Application app;
// public AppModule(Application app) {
// this.app = app;
// }
//}
//如果你的 Module 是这样:那就不需要
//@Module
//class NetworkModule {}
Builder appModule(AppModule module);
//✔ 唯一必需的方法
//这是 Builder 构建 Component 的出口,没有它你无法得到 AppComponent。
//Dagger 要求 Builder 必须有 build() 方法:
//返回类型必须是 Component 类型
//名字可以不是 build(),但必须有 一个方法返回 Component
AppComponent build();
}
void inject(MyApplication app);
}
Step 2:使用 Builder 创建
AppComponent appComponent = DaggerAppComponent.builder()
.application(this)
.appModule(new AppModule(this))
.build();
📝 Builder 特点:
🔧 使用 Factory 来创建 Component(比 Builder 更推荐) Step 1:写 Component
@Singleton
@Component(modules = {AppModule.class})
public interface AppComponent {
@Component.Factory
interface Factory {
AppComponent create(
@BindsInstance Application app,
AppModule appModule
);
}
void inject(MyApplication app);
}
Step 2:使用 Factory 创建
AppComponent appComponent =
DaggerAppComponent.factory().create(this, new AppModule(this));
📝 Factory 特点:
dependencies {
implementation 'com.google.code.gson:gson:2.10.1'
// Retrofit + OkHttp
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
implementation 'com.squareup.okhttp3:okhttp:4.11.0'
implementation 'com.squareup.okhttp3:logging-interceptor:4.11.0'
implementation 'com.squareup.retrofit2:adapter-rxjava3:2.9.0'
// RxJava3 + RxAndroid
implementation 'io.reactivex.rxjava3:rxjava:3.1.6'
implementation 'io.reactivex.rxjava3:rxandroid:3.0.2'
// Room with RxJava3 support
implementation 'androidx.room:room-runtime:2.6.1'
implementation 'androidx.room:room-rxjava3:2.6.1'
annotationProcessor 'androidx.room:room-compiler:2.6.1'
// Dagger2
implementation 'com.google.dagger:dagger:2.59.2'
annotationProcessor 'com.google.dagger:dagger-compiler:2.59.2'
implementation "com.google.dagger:dagger-android:2.59.2"
//implementation "com.google.dagger:dagger-android-support:2.59.2"
annotationProcessor "com.google.dagger:dagger-android-processor:2.59.2"
}
AppModule
@Module
public class AppModule {
@Provides
@Singleton
Context provideContext(Application application){
return application.getApplicationContext();
}
}
PostBean
@Entity(tableName = TABLE_NAME)
public class PostBean {
public static final String TABLE_NAME = "post_table";
@PrimaryKey
@SerializedName("id")
public int id;
@SerializedName("userID")
public int userId;
@SerializedName("title")
public String title;
@SerializedName("body")
public String body;
}
ApiService
public interface ApiService {
@GET("posts")
Single<List<PostBean>> getPostBean();
}
NetWorkModule
@Module
public class NetWorkModule {
private static final String BASE_URL = "https://jsonplaceholder.typicode.com/";
@Provides
@Singleton
HttpLoggingInterceptor provideLogging(){
HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
return loggingInterceptor;
}
@Provides
@Singleton
OkHttpClient provideOkHttpClient(HttpLoggingInterceptor loggingInterceptor){
return new OkHttpClient.Builder()
.addInterceptor(loggingInterceptor)
.callTimeout(30, TimeUnit.SECONDS)
.build();
}
@Provides
@Singleton
Gson provideGson(){
return new GsonBuilder().create();
}
@Provides
@Singleton
Retrofit provideRetrofit(OkHttpClient client , Gson gson){
return new Retrofit.Builder()
.baseUrl(BASE_URL)
.client(client)
.addConverterFactory(GsonConverterFactory.create(gson))
.addCallAdapterFactory(RxJava3CallAdapterFactory.createWithScheduler(Schedulers.io()))
.build();
}
@Provides
@Singleton
ApiService provideApiService(Retrofit retrofit){
return retrofit.create(ApiService.class);
}
}
PostBeanDao
@Dao
public interface PostBeanDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
Completable insertPosts(List<PostBean> posts);
@Query("SELECT * FROM "+PostBean.TABLE_NAME)
Flowable<List<PostBean>> observeAllPosts();
@Query("SELECT * FROM "+PostBean.TABLE_NAME)
Single<List<PostBean>> getAllPostsOnce();
}
PostBeanRepository
@Singleton
public class PostBeanRepository {
private ApiService apiService;
private PostBeanDao postBeanDao;
@Inject
public PostBeanRepository(ApiService apiService, PostBeanDao postDao){
this.apiService = apiService;
this.postBeanDao = postDao;
}
public Single<List<PostBean>> fetchAndStorePosts(){
return apiService.getPostBean().flatMap(
postBeans ->
postBeanDao.insertPosts(postBeans).andThen(
postBeanDao.getAllPostsOnce()
)
);
}
public Flowable<List<PostBean>> observeAllPosts(){
return postBeanDao.observeAllPosts();
}
}
AppDatabase
@Database(entities = {PostBean.class},version = 1,exportSchema = false)
public abstract class AppDatabase extends RoomDatabase {
abstract PostBeanDao postBeanDao();
}
DatabaseModule
@Module
public class DatabaseModule {
@Provides
@Singleton
AppDatabase provideAppDatabase(Context context){
return Room.databaseBuilder(context,AppDatabase.class,"sample.db")
.build();
}
@Provides
@Singleton
PostBeanDao providePostDao(AppDatabase db){
return db.postBeanDao();
}
}
MainViewModel
public class MainViewModel extends ViewModel {
private PostBeanRepository postBeanRepository;
@Inject
public MainViewModel(PostBeanRepository postBeanRepository){
this.postBeanRepository = postBeanRepository;
}
public Flowable<List<PostBean>> observeAllPosts(){
return postBeanRepository.observeAllPosts();
}
}
ViewModelKey
@Documented
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@MapKey
public @interface ViewModelKey {
Class<? extends ViewModel> value();
}
ViewModelModule
@Module
public abstract class ViewModelModule {
//Binds注解的作用
//告诉 Dagger:
//当需要 ViewModel 类型(或 Map 中的这个 Key)时,用 UserViewModel 来提供实现。
//因为 UserViewModel 是 ViewModel 的子类,所以可以安全转换。
//不需要写 return new UserViewModel(),Dagger 会自动生成代码调用构造函数(前提是构造函数有 @Inject)。
//在多 ViewModel 注入场景中,通常希望用一个 Map 来存放不同 ViewModel 的绑定:
//@IntoMap → 把绑定放进一个 Map,而不是单独提供。
//@ViewModelKey(UserViewModel.class) → 指定 Map 的 key。
//Map 类型最终是:Map<Class<? extends ViewModel>, Provider<ViewModel>>
//Dagger 会生成这个 Map,把不同的 ViewModel 绑定到对应 key。
@Binds
@IntoMap
@ViewModelKey(MainViewModel.class)
abstract ViewModel bindMainViewModel(MainViewModel mainViewModel);
//绑定一个通用的 ViewModelFactory(DaggerViewModelFactory)到 ViewModelProvider.Factory。
//这个工厂内部会使用上面 Map 来创建指定 ViewModel。
//好处:在 Activity/Fragment 中直接调用:ViewModel vm = new ViewModelProvider(this, factory).get(UserViewModel.class);
@Binds
abstract ViewModelProvider.Factory bindViewModelFactory(DaggerViewModelFactory daggerViewModelFactory);
}
ActivityBindingModule
import dagger.Module;
import dagger.android.ContributesAndroidInjector;
@Module
public abstract class ActivityBindingModule {
//把这个 Activity 的 injector factory 注册进去,供 DispatchingAndroidInjector 分发使用。
@ContributesAndroidInjector
abstract MainActivity bindMainActivity();
@ContributesAndroidInjector
abstract SecondActivity bindSecondActivity();
}
AppComponent
AndroidInjectionModule.class
//AndroidInjectionModule 是 Dagger Android 提供的内置 Module,它主要负责:
//提供 Activity、Fragment、Service 等 Android 组件的默认 Injector
//生成 DispatchingAndroidInjector,让你的 Application 能够提供 injector 给这些组件
//它本身一般不需要修改,Dagger 已经写好了。
//核心作用:
//提供 DispatchingAndroidInjector<Object>
//允许你在 Application 中写:
@Inject
DispatchingAndroidInjector<Object> androidInjector;
//这样 Application 就实现了 HasAndroidInjector 接口:
@Override
public AndroidInjector<Object> androidInjector() {
return androidInjector;
}
//Activity / Fragment / Service 执行 AndroidInjection.inject(this) 时,就可以拿到 injector
@Singleton
@Component(modules = {AndroidInjectionModule.class,AppModule.class,NetWorkModule.class, DatabaseModule.class, ViewModelModule.class})
public interface AppComponent {
void inject(MyApp app);
@Component.Factory
interface Factory{
AppComponent create(@BindsInstance Application application);
}
}
DaggerViewModelFactory
public class DaggerViewModelFactory implements ViewModelProvider.Factory {
private final Map<Class<? extends ViewModel>, Provider<ViewModel>> creators;
@Inject
public DaggerViewModelFactory(Map<Class<? extends ViewModel>, Provider<ViewModel>> creators) {
this.creators = creators;
}
@NonNull
@Override
public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
Provider<? extends ViewModel> creator = creators.get(modelClass);
if (creator == null) {
for (Map.Entry<Class<? extends ViewModel>, Provider<ViewModel>> entry : creators.entrySet()) {
if (modelClass.isAssignableFrom(entry.getKey())) {
creator = entry.getValue();
break;
}
}
}
if (creator == null) {
throw new IllegalArgumentException("Unknown ViewModel class: " + modelClass);
}
try {
return (T) creator.get();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
MyApp
//HasActivityInjector 是 Dagger Android 提供的接口:
public interface HasActivityInjector {
AndroidInjector<Activity> activityInjector();
}
//它的作用:
//让 Application 对外提供一个 Activity 注入器。也就是说,当你在 Activity 中调用:
AndroidInjection.inject(this)
//AndroidInjection 会自动向 Application 查询:
if (application instanceof HasActivityInjector) {
AndroidInjector<Activity> injector = application.activityInjector();
injector.inject(activity);
}
public class MyApp extends Application implements HasAndroidInjector {
private static AppComponent appComponent;
//这是 Dagger 自动生成的 多 Activity 注入器总路由器。
@Inject
DispatchingAndroidInjector<Object> androidInjector;
@Override
public void onCreate() {
super.onCreate();
//生成appComponent实例
appComponent = DaggerAppComponent.factory().create(this);
//这行代码执行后:
//dispatchingAndroidInjector 会被 Dagger 自动注入
//Application 现在具备 “Activity 注入器”
appComponent.inject(this);
}
public static AppComponent getAppComponent(){
return appComponent;
}
@Override
public AndroidInjector<Object> androidInjector() {
return androidInjector;
}
}
TestViewModelFactoryActivity
public class TestViewModelFactoryActivity extends AppCompatActivity {
//这个注入器的实例是AndroidInjectionModule.class提供的
@Inject
ViewModelProvider.Factory viewModelProviderFactory;
private MainViewModel mainViewModel;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
//让 Dagger 在 Activity onCreate() 之前,把需要的依赖注入到当前 Activity 中。
//为什么要放在 super.onCreate() 之前?
//一些依赖可能在 super.onCreate() 中用到
//Activity 的生命周期回调链会提前访问成员变量
//注入必须尽早,否则为空指针异常
//如果是 Fragment,则使用:AndroidSupportInjection.inject(this);
//和手工activityComponent.inject(activity)本质做的是同一件事,为 Activity 创建对应的子组件,然后调用 inject(activity) 把依赖注入进去。
AndroidInjection.inject(this);
super.onCreate(savedInstanceState);
mainViewModel = new ViewModelProvider(this,viewModelProviderFactory).get(MainViewModel.class);
setContentView(R.layout.activity_main);
}
public void goSecondAcitivty(View view){
Intent intent = new Intent(TestViewModelFactoryActivity.this, SecondActivity.class);
startActivity(intent);
}
}
✅AndroidInjection.inject(this) 和 “手工 activityComponent.inject(activity)” 的本质功能 它们本质做的是同一件事:为 Activity 创建对应的子组件,然后调用 inject(activity) 把依赖注入进去。 区别在于: AndroidInjection.inject(this):自动注入,子组件自动创建,依赖 dagger-android 手写 activityComponent.inject(activity):手工注入,子组件手动创建,完全手动管理 ✅ 方式 1:AndroidInjection.inject(this)(自动注入) 这个方式依赖: HasActivityInjector DispatchingAndroidInjector<Activity> @ContributesAndroidInjector AndroidInjection.inject(this) 你只要: ✔ Application 中注入 androidInjector
DaggerAppComponent.create().inject(this);
✔ 每个 Activity 里写:
AndroidInjection.inject(this);
super.onCreate(savedInstanceState);
✔ Dagger 自动为每个 Activity 生成子 Component:
@ContributesAndroidInjector
abstract MyActivity contributeMyActivity();
✅优点 无需自己写 Component、Builder、inject 方法,Dagger 全自动处理 模块化好:每个 Activity 的 module 自动关联 代码极简 避免因忘记 inject 造成的 null 更适合大型项目(几十上百个 Activity) 缺点 依赖 dagger-android(已停止维护,但仍稳定) ✅ 方式 2:手写 ActivityComponent 并手动注入 你可能要写很多代码: ✔ 定义 ActivityComponent
@ActivityScope
@Component(dependencies = AppComponent.class, modules = XActivityModule.class)
interface XActivityComponent {
void inject(XActivity activity);
}
✔ 手动创建 Component
component = DaggerXActivityComponent.builder()
.appComponent(((MyApp)getApplication()).getAppComponent())
.build();
component.inject(this);
✅优点 不依赖 dagger-android,完全纯 Dagger,掌控更强 对非常复杂的组件结构可能更灵活 缺点 样板代码巨大 你要给每个 Activity 写自己的 component 容易忘记调用 inject() → 注入失败 模块化差