不幸的是,我什至没有使用最简单的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";
}
}
房间模块
@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
放在需要Context的位置)。这就是问题所在-
RoomModule#getAppContext()
似乎是错误的可能来源吗? DBHelper
可能会很好,因为它是一个单例,并且一旦创建,理论上应该可以在任何地方使用。是否要向此人@Provides public Context getAppContext()
添加一些限定词,以使该解决方案或多或少没有漏洞?还是有更好的方法为DBHelper
构造函数提供上下文? 最佳答案
首先,删除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";
}
}
Dcc为您创建了
DBHelper
中的provideRoomDao
实例。为此,Dagger在@Inject
的构造函数上需要一个DBHelper
批注。由于您自己实例化RoomDAOImpl
,因此无需将@Inject
批注添加到RoomDAOImpl
的构造函数。