java如何在Dagger 1中使用Singleton。十、
我读了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
是不够的
# 1 楼答案
简单、简短的答案解决了一个小的设计缺陷,你的问题如下。与其创建一个新的
ObjectGraph
来在SomeServiceImpl
中注入SomeDataDAO
实例,不如将SomeDataDAO
传递给构造函数。这实际上就是依赖项注入的典型含义:使用某个对象的构造函数来注入其依赖项:这就是魔法发生的地方。注意到构造函数的
@Inject
注释了吗?它告诉Dagger在请求SomeServiceImpl
的实例时使用此构造函数,并查询ObjectGraph
的参数所以当你有了下面的
Provides
方法时,Dagger已经知道SomeServiceImpl
依赖于SomeDataDAO
,并使用provideSomeDataDAO
方法来提供那个实例。而且,嘿,这是一个单例,所以这是与这个ObjectGraph
检索的SomeDataDAO
的任何其他实例完全相同的实例事实上,你不想太频繁地使用
ObjectGraph.inject(...)
,你实际上想要使用上面的方法。但是,在某些情况下,您无法决定构造函数的外观。例如,在Android中,这些类包括Activity
和View
类。对于这些特殊情况,创建了ObjectGraph.inject
,所以您仍然可以使用Dagger注入依赖项最后一点:在}。您可能知道,这是处理实例字段的首选方法,使用可注入构造函数可以实现这一点
SomeServiceImpl
中,我做了someDataDAO
{原来这个答案一点也不短:O)