我读过Christian Gruber的post,我开始想知道如何使用应用程序范围的单身人士。
在我的应用程序中,我有一个类DBHelper
,其主要目的是保存我的数据库的密钥。我还有很多(至少两个)不同的DAO。
现在 - 我没有看到为什么我的几个活动/类需要的不仅仅是单个DAO实例。更重要的是,为什么DAO只需要DBHelper
的实例?我非常确定他们可以分享,尤其是我不能预测两个DAO同时希望对我的数据库执行某些操作的情况。所以让我们看一些课程:
DBHelper
@Singleton
public class DBHelper extends SQLiteOpenHelper {
//some not relevant configuration stuff
private Context context;
@Inject
public DBHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
this.context = context;
}
@Override
public void onCreate(SQLiteDatabase db) {
//db.execSQL, creating tables and stuff
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
//dropping tables, creating a new one
onCreate(db);
}
}
DAO
public interface SomeDataDAO {
void hai();
}
public class SomeDataDAOImpl implements SomeDataDAO {
private DBHelper dbHelper;
public SomeDataDAOImpl(DBHelper dbHelper){
this.dbHelper = dbHelper;
}
@Override
public void hai() {
SQLiteDatabase database = dbHelper.getWritableDatabase();
dbHelper.doSomeDatabaseStuff()
}
}
SomeDataModule
@Module(
injects = { MainActivity.class, SomeServiceImpl.class }
)
public class SomeDataModule {
private Context appContext;
@Provides @Singleton
public SomeDataDAO provideSomeDataDao(DBHelper dbHelper){
return new SomeDataDAOImpl(dbHelper);
}
@Provides @Singleton
public ISomeService provideSomeService(SomeServiceImpl impl){
return impl;
}
@Provides
public Context getAppContext(){
return this.appContext;
}
public SomeDataModule(){
this.appContext = MainActivity.getAppContext();
}
}
现在让我们看两个依赖性消费者的例子
public class MainActivity extends ActionBarActivity {
@Inject
SomeDataDAO someDataDAO;
private ObjectGraph objectGraph;
@Inject
ISomeService someService;
private static Context appContext;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
appContext = getApplicationContext();
objectGraph = ObjectGraph.create(SomeDataModule.class);
objectGraph.inject(this);
someService.doSomeStuff();
}
public static Context getAppContext() {
return appContext;
}
}
public class SomeServiceImpl implements ISomeService {
private ObjectGraph objectGraph;
@Inject public SomeDataDAO someDataDAO;
public SomeServiceImpl(){
objectGraph = ObjectGraph.create(GraphDataModule.class);
objectGraph.inject(this);
}
public void doSomeStuff(){
someDataDAO.hai();
}
}
它有效,但是当我inject(this)
两次时,Dagger显然创建了两个DBHelper
的实例,因为它认为"一个单例来自一个图形实例"。如何将SomeDataModule
包裹在ApplicationModule
中,因此我在整个应用中只有一个DBHelper
个实例?不幸的是,将@Singleton
添加到DBHelper
是不够的。
答案 0 :(得分:3)
解决轻微设计缺陷的简单,简短和答案,以及您的问题如下。您应该将ObjectGraph
传递给构造函数,而不是创建新的SomeDataDAO
以在SomeServiceImpl
中注入SomeDataDAO
实例。这实际上是依赖注入通常意味着:使用某个对象的构造函数来注入其依赖项:
public class SomeServiceImpl implements ISomeService {
private final SomeDataDAO someDataDAO;
@Inject
public SomeServiceImpl(SomeDataDAO someDataDAO){
this.someDataDAO = someDataDAO;
}
public void doSomeStuff(){
someDataDAO.hai();
}
}
现在这就是魔术发生的地方。注意构造函数的@Inject
注释?只要请求SomeServiceImpl
的实例,它就会告诉Dagger使用此构造函数,并向ObjectGraph
查询其参数。
因此,当您在下面使用此Provides
方法时,Dagger已经知道SomeServiceImpl
取决于SomeDataDAO
,并使用您的provideSomeDataDAO
方法来提供该实例。而且,嘿,它是一个单例,所以这与SomeDataDAO
检索到的ObjectGraph
的任何其他实例完全相同!
@Provides @Singleton
public ISomeService provideSomeService(SomeServiceImpl impl){
return impl;
}
事实上,您不想经常使用ObjectGraph.inject(...)
,实际上您想要使用上述方法。但是有些情况下你没有决定构造函数是什么样的。例如,在Android中,这些是Activity
和View
类。对于这些特殊情况,ObjectGraph.inject
已创建,因此您仍然可以使用Dagger注入依赖项。
最后注意事项:在SomeServiceImpl
我已someDataDAO
private
。您可能知道,这是处理实例字段的首选方法,并且使用可注入构造函数可以实现此目的。
原来这个答案根本不是那么简短:O)