【问题标题】:Using Singleton SQLiteHelper in Service在服务中使用单例 SQLiteHelper
【发布时间】:2016-03-30 17:50:37
【问题描述】:

我有一个在 SQLite 中存储数据的服务。我希望该服务在应用程序关闭时继续运行。 (刷出)但是 getInstance() 在应用程序被销毁时返回 null。即使在我的应用程序关闭后,我怎样才能让它保持活力?

我的数据库单例类:

public class DbManager {
    private static DbManager instance;
    private CipherDbHelper dbHelper;

    private DbManager() {

    }

    private DbManager(Context context, String password) {
        SQLiteDatabase.loadLibs(context);
        dbHelper = new CipherDbHelper(context, password);
    }

    public static void init(Context context, String password) {
        instance = new DbManager(context, password);
    }

    public static DbManager getInstance() {
        if (instance == null) {
            Log.e("DbManager", "Can't access DbManager : instance is null.")
        }
        return instance;
    }

    //Closing
    public void closeDatabase() {
        dbHelper.close();
        dbHelper = null;
        instance = null;
    }

    public <D extends Dao<T, String>, T> D getDAO(Class<T> clz) throws SQLException {
        return dbHelper.getDao(clz);
    }


}

【问题讨论】:

  • 不要个人认为,但您可能会被否决,因为您得到的异常实际上是硬编码在您的代码中,而不是实际的异常消息。
  • “初始问题”是什么意思?你让它听起来像“我得到了这个例外,为什么?”而且您发布的代码似乎是因为您的变量为空,因此抛出异常是因为它被编码为这样做。

标签: java android sqlite android-service intentservice


【解决方案1】:

第 1 步:删除 closeDatabase() 和任何调用它的代码。

第 2 步:让 getDatabase() 返回 null 而不是抛出异常,或者让它抛出自定义异常而不是 IllegalArgumentException

第 3 步:如果服务从其 getDatabase() 调用中获得 null(或者它捕获您的自定义异常),让它引发 Notification 告诉用户“我需要你再次登录”并且跳过应该做的任何工作。

从根本上说,您有一个架构问题:Android 进程是短暂的。这样做的一个后果是,在后台使用加密数据库通常是不可能的。流程结束后,您将失去对数据库(使用用户密码解锁)的访问权限,需要用户重新登录。

你可以使用前台服务(通过startForeground())来减少你的进程被终止的机会,但这会给用户带来成本(总是可见的Notification,不使用过多CPU的可能性- 真正的背景工作等)。

【讨论】:

  • 方法 closeDatabase() 从未被调用,所以这不是问题。那么,SQLCipher 仅在应用程序运行时才有效?那么我可以使用两个数据库,一个加密一个不加密吗?谢谢
  • @Jaythaking:“那么,SQLCipher 仅在应用程序运行时才有效?” -- 我更倾向于将其描述为“SQLCipher 需要密码,您只能通过您的 UI 从用户那里获取密码”。 “那我可以使用两个数据库,一个加密一个不加密吗?” -- 当然,虽然我不能说这是否解决了用户的安全问题。
  • "SQLCipher 需要密码,您只能通过用户界面从用户那里获取密码" 我会在加密数据库解锁后启动服务。所以它不再需要密码,除非它是当应用程序被杀死时被破坏了没有?
  • @Jaythaking:“所以它不应该再需要密码了,除非它在应用程序被杀死时被销毁,不是吗?” ——只要你的流程还在。一旦 Android 终止您的进程,您将无法再访问数据库,直到您再次要求用户输入密码。
  • 我将只使用另一个数据库,因为这些特定数据不需要是私有的。非常感谢您的帮助
【解决方案2】:

要在后台运行任务,您需要使用Service


在拨打DBManager.getInstance()之前拨打DBManager.init(context)即可;因为在您调用 init 方法之前,您的实例仍然是 null

【讨论】:

    【解决方案3】:

    对于在使用单例类获取帮助器实例的服务中访问 SQLite 数据库(加密或未加密)时遇到相同问题的人。这是我解决问题的方法。只需将服务的上下文传递给 SQLiteHelper 以再次加载 lib 并重新生成帮助程序实例。然后一旦应用关闭(通过刷出)它就不会被破坏

    在我的示例中,我在服务的 onCreate 方法中调用了它:

        DbManager.init(TrackingService.this, "examplePassword"));
    

    【讨论】:

      猜你喜欢
      • 2021-09-08
      • 1970-01-01
      • 2019-10-22
      • 2019-06-21
      • 1970-01-01
      • 1970-01-01
      • 2018-08-07
      • 1970-01-01
      • 2023-03-03
      相关资源
      最近更新 更多