不幸的是我甚至没有使用最简单的Dagger例子。让我们来看看我的代码(我删除了大部分UI和自动生成的代码,因为它不相关):
我的活动
public class MainActivity extends ActionBarActivity {
@Inject
RoomDAO roomDAO;
private ObjectGraph objectGraph;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
objectGraph = ObjectGraph.create(RoomModule.class);
roomDAO = objectGraph.get(RoomDAO.class);
roomDAO.hai();
}
}
RoomDAO& RoomDAOImpl
public interface RoomDAO {
String hai();
}
public class RoomDAOImpl implements RoomDAO {
private DBHelper dbHelper;
@Inject
public RoomDAOImpl(){
//I tried even this constructor in case dbHelper was the guy causing problems,
//but it wasn't!
}
public RoomDAOImpl(DBHelper dbHelper){
this.dbHelper = dbHelper;
}
@Override
public String hai() {
return "oh hai";
}
}
RoomModule
@Module(
injects = {MainActivity.class},
library = true
)
public class RoomModule {
@Provides @Singleton
public RoomDAO provideRoomDao(){
return new RoomDAOImpl();
}
}
DBHelper
没有任何有趣的东西(只是一些小的数据库内容,onCreate,onUpdate,更不用说了)。
我认为行roomDAO = objectGraph.get(RoomDAO.class);
会使Dagger(或多或少)调用RoomModule#provideRoomDao()
并使我成为一个漂亮的,全新的RoomDAOImpl对象(如果已经创建了它,则从天空中取出它)。但是,我的图表在RoomDAO
中没有injectableTypes
,因此在调用roomDAO = objectGraph.get(RoomDAO.class);
时,我的应用在ObjectGraph#getInjectableTypeBinding
行失败(因为moduleClass == null
)。我错过了什么?
修改
好的,可能现在是时候展示DBHelper的样子了。
public class DBHelper extends SQLiteOpenHelper {
// (...) not relevant config stuff i.e. DATABASE_NAME, DATABASE_VERSION
@Inject
public DBHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
//(...) creating tables
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
//(...) updating tables
}
}
@Module(
injects = {MainActivity.class}
)
public class RoomModule {
@Provides @Singleton
public RoomDAO provideRoomDao(DBHelper dbHelper){
return new RoomDAOImpl(dbHelper);
}
@Provides
public Context getAppContext(){
return MainActivity.getAppContext();
}
}
我决定使用你建议的第二种方法,因为它看起来更像Spring,我对此更熟悉。
MainActivity.getAppContext();
是一个静态方法,它返回静态字段Context的值。这有点令人尴尬,但如果涉及到Context,我会非常无知,因为我从未见过它的实际用法(我总是将this
放在我需要的上下文中。)
这就是问题所在 - RoomModule#getAppContext()
似乎是错误的可能来源吗? DBHelper
可能会很好,因为它是一个单身人士,一旦创建它应该在理论上可以在任何地方使用。是否为这个人@Provides public Context getAppContext()
添加了一些限定符,以使这个解决方案或多或少地免于错误?或者可能有更好的方法为DBHelper
构造函数提供上下文?
答案 0 :(得分:1)
首先,删除library = true
行。不要只添加library = true
或complete = false
,尤其是在基本示例中。这些行压制了有用的警告。
运行应用程序时,您将获得IllegalArgumentException
:
Caused by: java.lang.IllegalArgumentException: No inject registered for tmp.RoomDAO. You must explicitly add it to the 'injects' option in one of your modules.
有两种方法可以使用ObjectGraph
或get(...)
从inject(...)
检索实例。
使用get(...)
时,您需要将尝试获取的类添加到模块中的injects
选项中(例如异常告诉您):
@Module(injects = {MainActivity.class, RoomDAO.class})
这将使您的应用程序正常运行。您实际上不需要@Inject
字段上的RoomDAO
注释。
另一种方法是使用inject
, 需要@Inject
注释。 inject
查看类的带注释字段,并使用ObjectGraph
为它们分配值。使用此方法,您无需将RoomDAO
添加到模块的injects
选项中:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
objectGraph = ObjectGraph.create(RoomModule.class);
objectGraph.inject(this);
roomDAO.hai();
}
最后,您的RoomDAOImpl
取决于DBHelper
。为了完整起见,您可以这样做:
DBHelper:
public class DBHelper {
@Inject
public DBHelper() {
}
}
RoomModule:
@Module(
injects = {MainActivity.class}
)
public class RoomModule {
@Provides
@Singleton
public RoomDAO provideRoomDao(DBHelper dbHelper) {
return new RoomDAOImpl(dbHelper);
}
}
RoomDAOImpl:
public class RoomDAOImpl implements RoomDAO {
private final DBHelper mDBHelper;
public RoomDAOImpl(final DBHelper dbHelper) {
mDBHelper = dbHelper;
}
@Override
public String hai() {
return "oh hai";
}
}
Dagger为您创建DBHelper
中的provideRoomDao
个实例。为此,Dagger需要@Inject
的构造函数上的DBHelper
注释。由于您自己实例化RoomDAOImpl
,因此无需将@Inject
注释添加到RoomDAOImpl
的构造函数中。