6

我正在使用SQLite Asset Helper库来处理设置和升级我的应用程序数据库的繁琐工作。它工作得非常好,但不幸的是我还没有找到一种方法来通知用户何时库:

A) 首次加载数据库(通过从 \assets\databases\ 文件夹中解压缩)

或者

B) 升级数据库(使用 \assets\datates 中升级的数据库文件中的信息)

我尝试将此代码放在我的应用程序的主 Activity.onCreate() 中,认为我可以在主线程上加载数据库(如果它不存在),同时使用不可关闭的 AlertDialog 分散用户的注意力:

    File dbFile=this.getDatabasePath("gShoJMDict");
    Boolean dbExists = dbFile.exists();
    Log.i("ActivityStartScreen", String.valueOf(dbExists));

    if(!dbExists)
    {
        DialogFirstRun dialogFirstRun = new DialogFirstRun();
        dialogFirstRun.show(getSupportFragmentManager(), "dialogFirstRun");
        dialogFirstRun.setCancelable(false);
        DictHelper helper = new DictHelper(this);
        helper.getReadableDatabase();
        helper.close();
        dialogFirstRun.dismiss();
    }

不幸的是,SQLite Asset Helper 似乎在 onCreate() 之前检查数据库是否存在(基于 LogCat 条目),因此当上述代码块运行时,数据库已经存在,因此对话框永远不会出现。

我正在使用 ContentProvider,并且我已经验证我只是从 query() 或 update() 中调用 getReadableDatabase()。我的 ContentProvider 的 onCreate() 看起来像这样......

@Override
public boolean onCreate()
{
    // Load our database
    gdb = new JMDictHelper(getContext());
    return true;
}

...但尽管移动gdb = new JMDictHelper(getContext());进入 query() 或 update(),SQLite Asset Helper 库仍然会在我通知用户之前加载数据库。

在这种情况下我可以做些什么来拦截数据库的初始设置或升级并通知用户应用程序正忙于执行这些任务?现在,该应用程序只是坐在那里,直到库完成之前什么都不做——这对于测试来说很好,因为我知道可以期待它,但是当我准备好让应用程序上线时,我不能就这样离开它。

4

2 回答 2

6

以防万一您仍然对此感到疑惑或其他任何人有这个问题,这里有一个我刚刚实现的类似问题的解决方案。SQLiteAssetHelper 在调用 getReadableDatabase() 或 getWritableDatabase() 之前不会复制数据库。如果在 MainActivity.onCreate() 之前调用了其中一种方法,则可能是因为您在 ContentProvider 的 onCreate() 方法中调用了它。这是文档中的方法描述:

实现它以在启动时初始化您的内容提供程序。在应用程序启动时,为应用程序主线程上的所有注册内容提供程序调用此方法。它不能执行冗长的操作,否则应用程序启动将被延迟。

您应该将重要的初始化(例如打开、升级和扫描数据库)推迟到使用内容提供程序(通过 query(Uri, String[], String, String[], String), insert(Uri, ContentValues) 等) . 延迟初始化可保持应用程序快速启动,在不需要提供程序时避免不必要的工作,并阻止数据库错误(例如磁盘已满)停止应用程序启动。

如果您使用 SQLite,SQLiteOpenHelper 是一个有用的实用程序类,它可以轻松管理数据库,并且会自动延迟打开直到第一次使用。如果您确实使用 SQLiteOpenHelper,请确保避免从此方法调用 getReadableDatabase() 或 getWritableDatabase()。(相反,覆盖 onOpen(SQLiteDatabase) 以在首次打开数据库时对其进行初始化。)

当您的 ContentProvider 被实际访问时,您可以调用 getReadableDatabase() 或 getWritableDatabase(),如此所述。

现在您的 ContentProvider 没有阻止,您可以检查数据库是否存在于 MainActivity.onCreate() 中,如有必要,在显示 ProgressDialog 时将其复制到后台线程中:

// Create an AsyncTask to copy the database in a background thread while
// displaying a ProgressDialog.
private class LoadDatabaseTask extends AsyncTask<Context, Void, Void> {
    Context mContext;
    ProgressDialog mDialog;

    // Provide a constructor so we can get a Context to use to create
    // the ProgressDialog.
    LoadDatabasesTask(Context context) {
        super();
        mContext = context;
    }

    @Override
    protected void onPreExecute() {
        super.onPreExecute();
        mDialog = new ProgressDialog(mContext);
        mDialog.setMessage(mContext.getString("Loading database..."));
        mDialog.show();
    }

    @Override
    protected Void doInBackground(Context... contexts) {
        // Copy database.
        new MyAssetHelper(contexts[0]).getReadableDatabase();
        return null;
    }

    @Override
    protected void onPostExecute(Void result) {
        super.onPostExecute(result);
        mDialog.dismiss();
    }
}

@Override
protected void onCreate(Bundle savedInstanceState) {
    // ...

    // Install databases if necessary.
    File database = getDatabasePath(DB_NAME);
    if (!database.exists()) {
        new LoadDatabaseTask(this).execute(this, null, null);
    }

    // ...
}
于 2013-08-26T22:56:28.623 回答
2

源代码表明,AssetHelper 正确地继承自 SqliteOpenHelper。无需查看任何代码或 logcat,在主 Activity 的 onCreate 之前可以创建数据库的唯一合理的地方是一些类静态初始化(如果您不使用 Application 对象)。检查一下。

至于通知:当数据未准备好时使用 EmptyView 占位符并使用 Loaders,因为:

  1. 它们不会阻塞用户界面:用户可以在 EmptyView 中看到数据已被处理,甚至可以暂时离开活动。

  2. 它们不会因 Activity 的破坏而死亡,并且可以重用。

  3. 他们是标准的。

于 2013-05-23T19:50:13.897 回答