如何在Dagger 1.x中使用Singleton?

时间:2014-12-02 19:27:02

标签: java android dagger

我读过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 个答案:

答案 0 :(得分:3)

解决轻微设计缺陷的简单,简短和答案,以及您的问题如下。您应该将ObjectGraph传递给构造函数,而不是创建新的SomeDataDAO以在SomeServiceImpl中注入SomeDataDAO实例。这实际上是依赖注入通常意味着:使用某个对象的构造函数来注入其依赖项:

public class SomeServiceImpl implements ISomeService {

    private final SomeDataDAO someDataDAO;

    @Inject
    public SomeServiceImpl(SomeDataDAO someDataDAO){
        this.someDataDAO = someDataDAO;
    }

    public void doSomeStuff(){
         someDataDAO.hai();
    }
}

现在这就是魔术发生的地方。注意构造函数的@Inject注释?只要请求SomeServiceImpl的实例,它就会告诉Dagger使用此构造函数,并向ObjectGraph查询其参数。

因此,当您在下面使用此Provides方法时,Dagger已经知道SomeServiceImpl取决于SomeDataDAO,并使用您的provideSomeDataDAO方法来提供该实例。而且,嘿,它是一个单例,所以这与SomeDataDAO检索到的ObjectGraph的任何其他实例完全相同!

  @Provides @Singleton
  public ISomeService provideSomeService(SomeServiceImpl impl){
         return impl;
  }

事实上,您不想经常使用ObjectGraph.inject(...),实际上您想要使用上述方法。但是有些情况下你没有决定构造函数是什么样的。例如,在Android中,这些是ActivityView类。对于这些特殊情况,ObjectGraph.inject已创建,因此您仍然可以使用Dagger注入依赖项。

最后注意事项:在SomeServiceImpl我已someDataDAO private。您可能知道,这是处理实例字段的首选方法,并且使用可注入构造函数可以实现此目的。

原来这个答案根本不是那么简短:O)