匕首不断拒绝注入依赖

时间:2014-11-30 21:45:49

标签: android dagger

不幸的是我甚至没有使用最简单的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构造函数提供上下文?

1 个答案:

答案 0 :(得分:1)

首先,删除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";
    }
}

Dagger为您创建DBHelper中的provideRoomDao个实例。为此,Dagger需要@Inject的构造函数上的DBHelper注释。由于您自己实例化RoomDAOImpl,因此无需将@Inject注释添加到RoomDAOImpl的构造函数中。