场景是假设:我们有一个 LoginActivity,需要一个 LoginViewModel,它又依赖 UserRepository,UserRepository 再依赖一个 ApiService(网络请求)。
1. 业务层类:ApiService、UserRepository、LoginViewModel
1.1 ApiService(第三方/网络封装类,通常不能直接 @Inject 构造)
arduino
// ApiService.java
public class ApiService {
private final String baseUrl;
public ApiService(String baseUrl) {
this.baseUrl = baseUrl;
}
public boolean login(String username, String password) {
// 假装这里发网络请求
System.out.println("Request to " + baseUrl + " login: " + username);
// 简化起见直接返回 true
return true;
}
}
逐行说明:
-
public class ApiService {定义一个普通的 Java 类,代表网络层封装。
-
private final String baseUrl;用于保存接口域名。
-
public ApiService(String baseUrl) { ... }构造函数需要一个
baseUrl参数,这个在项目中常常来自配置或 BuildConfig。注意:我们没有 加
@Inject,因为往往这个类来自三方库或比较通用,习惯用 Module 提供。 -
public boolean login(...) { ... }一个模拟登录方法,这里只是打印日志并返回
true。
1.2 UserRepository(可以使用构造函数注入)
arduino
// UserRepository.java
import javax.inject.Inject;
public class UserRepository {
private final ApiService apiService;
@Inject
public UserRepository(ApiService apiService) {
this.apiService = apiService;
}
public boolean login(String username, String password) {
// 业务仓库层,把网络调用组织在一起
return apiService.login(username, password);
}
}
逐行说明:
import javax.inject.Inject; 引入 JSR-330 标准的 @Inject 注解(Dagger 支持)。
public class UserRepository { 仓库层,封装数据访问(网络、本地缓存等)。
private final ApiService apiService; 依赖 ApiService。
@Inject 标记这个构造函数是 Dagger 可用的"注入点": Dagger 知道如果有人需要 UserRepository,要用这个构造函数来创建,同时自动注入 ApiService。
public UserRepository(ApiService apiService) { ... } 构造函数依赖 ApiService,Dagger 会从依赖图中找到对应的提供方式。
public boolean login(...) { ... } 对外暴露业务方法,内部使用 apiService.login(...)。
1.3 LoginViewModel(同样用构造函数注入)
kotlin
// LoginViewModel.java
import javax.inject.Inject;
public class LoginViewModel {
private final UserRepository userRepository;
@Inject
public LoginViewModel(UserRepository userRepository) {
this.userRepository = userRepository;
}
public boolean performLogin(String username, String password) {
// 可以在这里做一些校验、状态管理等
if (username == null || username.isEmpty()) {
System.out.println("Username empty");
return false;
}
return userRepository.login(username, password);
}
}
逐行说明:
public class LoginViewModel { 表示页面逻辑层(这里不用 AndroidX ViewModel,为了示例简单)。
private final UserRepository userRepository; 依赖仓库层。
@Inject + 构造函数 告诉 Dagger:如果有人需要 LoginViewModel,就用这个构造函数,并从依赖图中注入一个 UserRepository。
performLogin(...) 页面逻辑:进行简单校验后,调用仓库层完成登录。
2. Dagger Module:提供 ApiService
因为 ApiService 构造函数需要 baseUrl,我们希望统一在一个地方配置它,用 Dagger 的 @Module + @Provides。
typescript
// NetworkModule.java
import dagger.Module;
import dagger.Provides;
import javax.inject.Singleton;
@Module
public class NetworkModule {
private final String baseUrl;
public NetworkModule(String baseUrl) {
this.baseUrl = baseUrl;
}
@Singleton
@Provides
ApiService provideApiService() {
return new ApiService(baseUrl);
}
}
逐行说明:
@Module 声明这是一个 Dagger Module,里面的方法会用于提供依赖对象。
public class NetworkModule { 定义网络相关的依赖提供模块。
private final String baseUrl; + 构造函数 模块本身也可以有构造函数,这样我们在创建 Component 时可以传入不同的配置(例如测试环境、生产环境用不同 baseUrl)。
@Singleton 声明本方法产生的对象在该 Component 生命周期内为单例。
@Provides 告诉 Dagger:这是一个"提供函数(Provider)",用来创建 ApiService 实例。
ApiService provideApiService() { return new ApiService(baseUrl); } 实际创建 ApiService;Dagger 会在有人需要 ApiService 时调用此方法。
3. Dagger Component:组装整个依赖图
java
// AppComponent.java
import javax.inject.Singleton;
import dagger.Component;
@Singleton
@Component(modules = { NetworkModule.class })
public interface AppComponent {
// 暴露一个方法:用于给 LoginActivity 注入字段
void inject(LoginActivity activity);
// 也可以选择暴露某些依赖(可选)
LoginViewModel loginViewModel();
}
逐行说明:
@Singleton 声明整个 Component 的作用域是单例;配合 Module 中的 @Singleton,可以保证 ApiService 等是在同一图中单例。
@Component(modules = { NetworkModule.class }) 告诉 Dagger:这个 Component 依赖哪些 Module 来提供对象。 这里指定 NetworkModule,让 Dagger 知道 ApiService 怎么创建。
public interface AppComponent { ... } Component 通常是一个接口,Dagger 会在编译期生成实现类 DaggerAppComponent。
void inject(LoginActivity activity); 声明一个"注入方法":表示 Dagger 有能力给 LoginActivity 中标记了 @Inject 的字段进行赋值。
LoginViewModel loginViewModel(); 可选:直接从 Component 获取某个对象实例,此处获取 LoginViewModel。
4. Android 层:LoginActivity 使用 Dagger 注入
scala
// LoginActivity.java
import android.os.Bundle;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import javax.inject.Inject;
public class LoginActivity extends AppCompatActivity {
@Inject
LoginViewModel loginViewModel;
private AppComponent appComponent;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 1. 构建 AppComponent
appComponent = DaggerAppComponent
.builder()
.networkModule(new NetworkModule("https://api.example.com"))
.build();
// 2. 对当前 Activity 进行依赖注入
appComponent.inject(this);
// 3. 使用注入好的 loginViewModel
boolean success = loginViewModel.performLogin("alice", "123456");
System.out.println("Login result: " + success);
}
}
逐行说明:
public class LoginActivity extends AppCompatActivity { 标准 Android Activity。
@Inject LoginViewModel loginViewModel; 这里是字段注入:表示 loginViewModel 的实例由 Dagger 来提供。 注意:此时还没有值,只有在执行 appComponent.inject(this); 之后才会被赋值。
private AppComponent appComponent; 保存一个 AppComponent 引用,方便后续使用。
onCreate(...) 是 Activity 生命周期入口。
onCreate 内部:
1.构建 AppComponent
ini
appComponent = DaggerAppComponent
.builder()
.networkModule(new NetworkModule("https://api.example.com"))
.build();
DaggerAppComponent 这是 Dagger 编译期自动生成的类名(规则:前面加 Dagger 前缀)。
.builder() 使用 Builder 模式构建 Component。
.networkModule(...) 这里给 Component 设置 NetworkModule,传入 baseUrl。 Dagger 知道 AppComponent 需要一个类型为 NetworkModule 的模块实例。
.build() 完成 Component 实例构建,内部会初始化依赖图。
2.对 Activity 注入
kotlin
appComponent.inject(this);
调用我们在 AppComponent 接口中定义的 inject(LoginActivity activity)。
Dagger 会扫描 LoginActivity 中标记了 @Inject 的字段(这里是 loginViewModel),并根据依赖图实例化 LoginViewModel:
为 LoginViewModel 的构造函数注入 UserRepository。
为 UserRepository 的构造函数注入 ApiService。
为 ApiService 调用 NetworkModule.provideApiService() 创建实例。
最终把组装好的 LoginViewModel 赋值给 loginViewModel 字段。
3.使用注入结果
ini
boolean success = loginViewModel.performLogin("alice", "123456");
此时 loginViewModel 已经是一个完整的对象,可以直接使用。
后续该 ViewModel 内部调用 Repository,Repository 调用 ApiService,整条依赖链都由 Dagger 管理。
5. 流程总结(从需求到对象的形成)
以 LoginActivity 想要使用 LoginViewModel 为主线:
Activity 声明需要 LoginViewModel(字段 @Inject LoginViewModel loginViewModel;)。
通过 DaggerAppComponent.builder().networkModule(...).build() 构建依赖图。
调用 appComponent.inject(this):
Dagger 发现需要为 LoginActivity.loginViewModel 提供实例;
查看 LoginViewModel 构造函数有 @Inject,需要 UserRepository;
找到 UserRepository 构造函数 @Inject,需要 ApiService;
发现 ApiService 没有 @Inject 构造函数,但有一个 @Provides ApiService provideApiService();
调用 NetworkModule.provideApiService() 得到 ApiService;
组装出 UserRepository、LoginViewModel,最后把 loginViewModel 赋给 Activity 字段。
全程不需要在 Activity 中写:
ini
ApiService api = new ApiService("...");
UserRepository repo = new UserRepository(api);
LoginViewModel vm = new LoginViewModel(repo);
而是完全由 Dagger 管理对象创建和依赖关系。
关键就是理清个对象之间的依赖关系。