了解用于 Android 开发的 Dagger 2
Understanding Dagger 2 for Android development
这是我的代码,它基于在 Internet 上找到的一些旧教程。 Dagger 2 的主站点上确实应该有一些示例,我发现很难理解如何实现所有这些。
为了运行做一个这么简单的应用,真的是辛苦了。我有两个问题:
我是否必须在每个 class 中调用 DaggerLoggerComponent 我想要获得一些组件,例如我的 Logger class?
另外,如何使 Logger class 的作用域成为单例?现在每次单击按钮都会创建一个新的记录器实例。
可能我不了解一些基本概念,我以前只在 Spring 中使用过依赖注入,所有这些对我来说都很奇怪。
public class MainActivity extends AppCompatActivity {
private Button button;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
init();
}
private void init(){
button = (Button)findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
LoggerComponent component = DaggerLoggerComponent.builder().loggerModule(new LoggerModule()).build();
component.getLogger().log("Hello!",MainActivity.this);
}
});
}
}
public class Logger {
private static int i = 0;
public Logger(){
i++;
}
public static int getI() {
return i;
}
public void log(String text, Context context){
Toast.makeText(context,text+" "+i,Toast.LENGTH_SHORT).show();
}
}
@Singleton
@Component(modules={LoggerModule.class})
public interface LoggerComponent {
Logger getLogger();
}
@Module
public class LoggerModule {
@Provides
@Singleton
Logger provideLogger(){
return new Logger();
}
}
Do I have to call DaggerLoggerComponent in every class I want to get some components like my Logger class?
对系统创建的所有 类 是,如应用程序、Activity 和服务。但对于您自己的 类,您不需要它。只需用 @inject 注释你的构造函数,dagger 就会提供你的依赖项。
Also how can I make the scope of the Logger class a singleton? Right
now every button click creates a new logger instance.
您的单例设置是正确的。但是您必须在 activity 创建(onCreate)后初始化组件一次,以便让匕首注入所有字段。如果您不需要立即使用 Logger 对象,也可以使用惰性注入功能。
@Inject
Logger logger;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
LoggerComponent component = DaggerLoggerComponent.builder().loggerModule(new LoggerModule()).build();
component.inject(this);
init();
}
然后你可以访问你的对象而不需要从组件中获取引用:
private void init(){
button = (Button)findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
logger.log("Hello!",MainActivity.this);
}
});
}
总结:
您必须在所有使用字段注入的 类 中初始化组件。
更新:
要进行实际的注入,你必须在你的组件中声明 inject() 方法,dagger 会自动实现它。此方法将负责提供任何用 @Inject 注释的对象。
答案是
public class MainActivity extends AppCompatActivity {
@OnClick(R.id.button) //ButterKnife
public void onClickButton() {
logger.log("Hello!");
}
@Inject
Logger logger;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Injector.INSTANCE.getApplicationComponent().inject(this);
ButterKnife.bind(this);
}
@Override
protected void onDestroy() {
ButterKnife.unbind(this);
super.onDestroy();
}
}
public class Logger {
private static int i = 0;
private CustomApplication customApplication;
public Logger(CustomApplication application) {
this.customApplication = application;
i++;
}
public static int getI() {
return i;
}
public void log(String text){
Toast.makeText(customApplication, text + " " + i,Toast.LENGTH_SHORT).show();
}
}
public interface LoggerComponent {
Logger logger();
}
@Module
public class ApplicationModule {
private CustomApplication customApplication;
public ApplicationModule(CustomApplication customApplication) {
this.customApplication = customApplication;
}
@Provides
public CustomApplication customApplication() {
return customApplication;
}
}
@Module
public class LoggerModule {
@Provides
@Singleton
Logger provideLogger(){
return new Logger();
}
}
@Singleton
@Component(modules={LoggerModule.class, ApplicationModule.class})
public interface ApplicationComponent extends LoggerComponent {
CustomApplication customApplication();
void inject(MainActivity mainActivity);
}
public class CustomApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
Injector.INSTANCE.initializeApplicationComponent(this);
}
}
public enum Injector {
INSTANCE;
private ApplicationComponent applicationComponent;
public ApplicationComponent getApplicationComponent() {
return applicationComponent;
}
void initializeApplicationComponent(CustomApplication customApplication) {
this.applicationComponent = DaggerApplicationComponent.builder()
.applicationModule(new ApplicationModule(customApplication))
.build();
}
}
This is currently our Dagger2 architecture.
编辑:这是来自我们正在制作的应用程序的 Retrofit 内容的实际代码:
public interface RecordingService {
ScheduledRecordsXML getScheduledRecords(long userId)
throws ServerErrorException;
}
public class RecordingServiceImpl
implements RecordingService {
private static final String TAG = RecordingServiceImpl.class.getSimpleName();
private RetrofitRecordingService retrofitRecordingService;
public RecordingServiceImpl(RetrofitRecordingService retrofitRecordingService) {
this.retrofitRecordingService = retrofitRecordingService;
}
@Override
public ScheduledRecordsXML getScheduledRecords(long userId)
throws ServerErrorException {
try {
return retrofitRecordingService.getScheduledPrograms(String.valueOf(userId));
} catch(RetrofitError retrofitError) {
Log.e(TAG, "Error occurred in downloading XML file.", retrofitError);
throw new ServerErrorException(retrofitError);
}
}
}
@Module
public class NetworkClientModule {
@Provides
@Singleton
public OkHttpClient okHttpClient() {
OkHttpClient okHttpClient = new OkHttpClient();
okHttpClient.interceptors().add(new HeaderInterceptor());
return okHttpClient;
}
}
@Module(includes = {NetworkClientModule.class})
public class ServiceModule {
@Provides
@Singleton
public RecordingService recordingService(OkHttpClient okHttpClient, Persister persister, AppConfig appConfig) {
return new RecordingServiceImpl(
new RestAdapter.Builder().setEndpoint(appConfig.getServerEndpoint())
.setConverter(new SimpleXMLConverter(persister))
.setClient(new OkClient(okHttpClient))
.setLogLevel(RestAdapter.LogLevel.NONE)
.build()
.create(RetrofitRecordingService.class));
}
//...
}
public interface RetrofitRecordingService {
@GET("/getScheduledPrograms")
ScheduledRecordsXML getScheduledPrograms(@Query("UserID") String userId);
}
public interface ServiceComponent {
RecordingService RecordingService();
//...
}
public interface AppDomainComponent
extends InteractorComponent, ServiceComponent, ManagerComponent, ParserComponent {
}
@Singleton
@Component(modules = {
//...
InteractorModule.class,
ManagerModule.class,
ServiceModule.class,
ParserModule.class
//...
})
public interface ApplicationComponent
extends AppContextComponent, AppDataComponent, AppDomainComponent, AppUtilsComponent, AppPresentationComponent {
void inject(DashboardActivity dashboardActivity);
//...
}
这是我的代码,它基于在 Internet 上找到的一些旧教程。 Dagger 2 的主站点上确实应该有一些示例,我发现很难理解如何实现所有这些。
为了运行做一个这么简单的应用,真的是辛苦了。我有两个问题:
我是否必须在每个 class 中调用 DaggerLoggerComponent 我想要获得一些组件,例如我的 Logger class?
另外,如何使 Logger class 的作用域成为单例?现在每次单击按钮都会创建一个新的记录器实例。
可能我不了解一些基本概念,我以前只在 Spring 中使用过依赖注入,所有这些对我来说都很奇怪。
public class MainActivity extends AppCompatActivity {
private Button button;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
init();
}
private void init(){
button = (Button)findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
LoggerComponent component = DaggerLoggerComponent.builder().loggerModule(new LoggerModule()).build();
component.getLogger().log("Hello!",MainActivity.this);
}
});
}
}
public class Logger {
private static int i = 0;
public Logger(){
i++;
}
public static int getI() {
return i;
}
public void log(String text, Context context){
Toast.makeText(context,text+" "+i,Toast.LENGTH_SHORT).show();
}
}
@Singleton
@Component(modules={LoggerModule.class})
public interface LoggerComponent {
Logger getLogger();
}
@Module
public class LoggerModule {
@Provides
@Singleton
Logger provideLogger(){
return new Logger();
}
}
Do I have to call DaggerLoggerComponent in every class I want to get some components like my Logger class?
对系统创建的所有 类 是,如应用程序、Activity 和服务。但对于您自己的 类,您不需要它。只需用 @inject 注释你的构造函数,dagger 就会提供你的依赖项。
Also how can I make the scope of the Logger class a singleton? Right now every button click creates a new logger instance.
您的单例设置是正确的。但是您必须在 activity 创建(onCreate)后初始化组件一次,以便让匕首注入所有字段。如果您不需要立即使用 Logger 对象,也可以使用惰性注入功能。
@Inject
Logger logger;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
LoggerComponent component = DaggerLoggerComponent.builder().loggerModule(new LoggerModule()).build();
component.inject(this);
init();
}
然后你可以访问你的对象而不需要从组件中获取引用:
private void init(){
button = (Button)findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
logger.log("Hello!",MainActivity.this);
}
});
}
总结: 您必须在所有使用字段注入的 类 中初始化组件。
更新: 要进行实际的注入,你必须在你的组件中声明 inject() 方法,dagger 会自动实现它。此方法将负责提供任何用 @Inject 注释的对象。
答案是
public class MainActivity extends AppCompatActivity {
@OnClick(R.id.button) //ButterKnife
public void onClickButton() {
logger.log("Hello!");
}
@Inject
Logger logger;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Injector.INSTANCE.getApplicationComponent().inject(this);
ButterKnife.bind(this);
}
@Override
protected void onDestroy() {
ButterKnife.unbind(this);
super.onDestroy();
}
}
public class Logger {
private static int i = 0;
private CustomApplication customApplication;
public Logger(CustomApplication application) {
this.customApplication = application;
i++;
}
public static int getI() {
return i;
}
public void log(String text){
Toast.makeText(customApplication, text + " " + i,Toast.LENGTH_SHORT).show();
}
}
public interface LoggerComponent {
Logger logger();
}
@Module
public class ApplicationModule {
private CustomApplication customApplication;
public ApplicationModule(CustomApplication customApplication) {
this.customApplication = customApplication;
}
@Provides
public CustomApplication customApplication() {
return customApplication;
}
}
@Module
public class LoggerModule {
@Provides
@Singleton
Logger provideLogger(){
return new Logger();
}
}
@Singleton
@Component(modules={LoggerModule.class, ApplicationModule.class})
public interface ApplicationComponent extends LoggerComponent {
CustomApplication customApplication();
void inject(MainActivity mainActivity);
}
public class CustomApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
Injector.INSTANCE.initializeApplicationComponent(this);
}
}
public enum Injector {
INSTANCE;
private ApplicationComponent applicationComponent;
public ApplicationComponent getApplicationComponent() {
return applicationComponent;
}
void initializeApplicationComponent(CustomApplication customApplication) {
this.applicationComponent = DaggerApplicationComponent.builder()
.applicationModule(new ApplicationModule(customApplication))
.build();
}
}
This is currently our Dagger2 architecture.
编辑:这是来自我们正在制作的应用程序的 Retrofit 内容的实际代码:
public interface RecordingService {
ScheduledRecordsXML getScheduledRecords(long userId)
throws ServerErrorException;
}
public class RecordingServiceImpl
implements RecordingService {
private static final String TAG = RecordingServiceImpl.class.getSimpleName();
private RetrofitRecordingService retrofitRecordingService;
public RecordingServiceImpl(RetrofitRecordingService retrofitRecordingService) {
this.retrofitRecordingService = retrofitRecordingService;
}
@Override
public ScheduledRecordsXML getScheduledRecords(long userId)
throws ServerErrorException {
try {
return retrofitRecordingService.getScheduledPrograms(String.valueOf(userId));
} catch(RetrofitError retrofitError) {
Log.e(TAG, "Error occurred in downloading XML file.", retrofitError);
throw new ServerErrorException(retrofitError);
}
}
}
@Module
public class NetworkClientModule {
@Provides
@Singleton
public OkHttpClient okHttpClient() {
OkHttpClient okHttpClient = new OkHttpClient();
okHttpClient.interceptors().add(new HeaderInterceptor());
return okHttpClient;
}
}
@Module(includes = {NetworkClientModule.class})
public class ServiceModule {
@Provides
@Singleton
public RecordingService recordingService(OkHttpClient okHttpClient, Persister persister, AppConfig appConfig) {
return new RecordingServiceImpl(
new RestAdapter.Builder().setEndpoint(appConfig.getServerEndpoint())
.setConverter(new SimpleXMLConverter(persister))
.setClient(new OkClient(okHttpClient))
.setLogLevel(RestAdapter.LogLevel.NONE)
.build()
.create(RetrofitRecordingService.class));
}
//...
}
public interface RetrofitRecordingService {
@GET("/getScheduledPrograms")
ScheduledRecordsXML getScheduledPrograms(@Query("UserID") String userId);
}
public interface ServiceComponent {
RecordingService RecordingService();
//...
}
public interface AppDomainComponent
extends InteractorComponent, ServiceComponent, ManagerComponent, ParserComponent {
}
@Singleton
@Component(modules = {
//...
InteractorModule.class,
ManagerModule.class,
ServiceModule.class,
ParserModule.class
//...
})
public interface ApplicationComponent
extends AppContextComponent, AppDataComponent, AppDomainComponent, AppUtilsComponent, AppPresentationComponent {
void inject(DashboardActivity dashboardActivity);
//...
}