【问题标题】:Handling SQLite singleton instances and its Context dependency in Android在 Android 中处理 SQLite 单例实例及其上下文依赖
【发布时间】:2016-07-24 14:37:28
【问题描述】:

我目前正在开发一个与 SQLite 数据库进行大量通信的 Android 项目。我也在尝试在应用程序中实现 MVP 框架。

我当前对 Singleton 实例的实现类似于以下内容。 (取自这篇文章:https://github.com/codepath/android_guides/wiki/Local-Databases-with-SQLiteOpenHelper

public class PostsDatabaseHelper extends SQLiteOpenHelper { 
  private static PostsDatabaseHelper sInstance;

  public static synchronized PostsDatabaseHelper getInstance(Context context) {
    if (sInstance == null) {
      sInstance = new PostsDatabaseHelper(context.getApplicationContext());
    }
    return sInstance;
  }

  private PostsDatabaseHelper(Context context) {
    super(context, DATABASE_NAME, null, DATABASE_VERSION);
  }
}

使用上面的现有代码,我在几个 Presenter 类中调用 getInstance 方法,将 Activity/Fragment 传递的 Context 对象传递给每个类。 Context 对象可以跨多个类传递。

我想在应用程序启动时只实例化一次 databaseHelper,而不是上面的代码,然后所有引用都将指向 getInstance 方法的变体,而没有上下文依赖。

编辑:我的主要目的是尽可能多地删除 Presenter 类中存在的 Context 对象,从而使代码“更干净”。因为所有对 getInstance 的调用都提供/注入相同类型的 Context(应用程序的上下文而不是特定于 Activity 的上下文),所以我认为不需要将 Context 对象作为参数。

public class PostsDatabaseHelper extends SQLiteOpenHelper { 
  private static PostsDatabaseHelper sInstance;

  // called by all other classes
  public static synchronized PostsDatabaseHelper getInstance() {
    if (sInstance == null) {
      //throw error
    }
    return sInstance;
  }

  // only called once at the start of the Application
  public static void instantiateInstance(Context context){
    sInstance = new PostsDatabaseHelper(context.getApplicationContext());
  }

  private PostsDatabaseHelper(Context context) {
    super(context, DATABASE_NAME, null, DATABASE_VERSION);
  }
} 

我想知道的是,这种方法会有什么缺点吗?谢谢!

【问题讨论】:

    标签: android singleton mvp sqliteopenhelper


    【解决方案1】:

    您正在用惰性初始化来换取静态初始化。

    通常,延迟初始化可以在应用程序的生命周期内分摊初始化成本。在这种情况下,它似乎不太重要,原因有两个:

    1. 几乎可以肯定您将需要此数据库。推迟初始化似乎不太可能完全避免这样做。
    2. Android 框架保证DBHelper 构造函数可以从UI 线程运行:这不是需要时间的。需要时间的是第一次调用getWriteableDatabase。 Helper 的懒惰创建几乎一无所获。

    您可能会考虑通过像这样在应用程序中初始化数据库来减少代码的复杂性:

    public class DBDrivenApp extends Application implements DBProvider {
    
      // ...
    
      private PostsDatabaseHelper db;
    
      // ...
    
      @Override
      public void onCreate() {
        super.onCreate();
        db = new PostsDatabaseHelper(this);
      }
    
      @Override
      public PostsDatabaseHelper getDB() { return db; }
    
      // ...
    }
    

    ...更好的是,使用 IoC 框架(如 Dagger2)来注入数据库实例,以便您可以在测试中模拟它。

    【讨论】:

    • 嗨,布莱克,感谢您的详细回答。我同意你的观点,使用延迟初始化的初始化成本可以忽略不计。我的主要目的是真正减少 Presenter 类中“上下文”对象的存在,从而使代码“更干净”。此外,由于对方法 getInstance 的所有调用实际上都提供了相同的应用程序上下文,我看不出为什么应该将 Context 对象作为参数传递给后续调用。如果传入的 Context 对象是特定于 Activity 的上下文,那么将其作为参数是有意义的。
    • 是的。我想我同意所有这些。如果您使用我建议的代码,则需要将 DBProvider 传递给您的 Presenter(顺便说一下,一个上下文和一个应用程序)。如果您的 Presenter 需要从数据库中获取内容,这似乎是合理的......
    • ... 或者,顺便说一句,如果这对你来说太老了,你可以做一些更 iOS 风格的事情,通过将 DBHelper 包装在事件总线上监听的东西中。然后,您甚至不必将 DBProvider 传递给 Presenter。
    猜你喜欢
    • 2020-04-13
    • 2010-10-02
    • 1970-01-01
    • 2021-08-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多