有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java如何在Dagger 1中使用Singleton。十、

我读了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) 个答案

  1. # 1 楼答案

    简单、简短的答案解决了一个小的设计缺陷,你的问题如下。与其创建一个新的ObjectGraph来在SomeServiceImpl中注入SomeDataDAO实例,不如将SomeDataDAO传递给构造函数。这实际上就是依赖项注入的典型含义:使用某个对象的构造函数来注入其依赖项:

    public class SomeServiceImpl implements ISomeService {
    
        private final SomeDataDAO someDataDAO;
    
        @Inject
        public SomeServiceImpl(SomeDataDAO someDataDAO){
            this.someDataDAO = someDataDAO;
        }
    
        public void doSomeStuff(){
             someDataDAO.hai();
        }
    }
    

    这就是魔法发生的地方。注意到构造函数的@Inject注释了吗?它告诉Dagger在请求SomeServiceImpl的实例时使用此构造函数,并查询ObjectGraph的参数

    所以当你有了下面的Provides方法时,Dagger已经知道SomeServiceImpl依赖于SomeDataDAO,并使用provideSomeDataDAO方法来提供那个实例。而且,嘿,这是一个单例,所以这是与这个ObjectGraph检索的SomeDataDAO的任何其他实例完全相同的实例

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

    事实上,你不想太频繁地使用ObjectGraph.inject(...),你实际上想要使用上面的方法。但是,在某些情况下,您无法决定构造函数的外观。例如,在Android中,这些类包括ActivityView类。对于这些特殊情况,创建了ObjectGraph.inject,所以您仍然可以使用Dagger注入依赖项

    最后一点:在SomeServiceImpl中,我做了someDataDAO{}。您可能知道,这是处理实例字段的首选方法,使用可注入构造函数可以实现这一点

    原来这个答案一点也不短:O)