不幸的是,我什至没有使用最简单的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 = truecomplete = 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.




有两种方法可以使用ObjectGraphget(...)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的构造函数。

10-08 19:09