我正在使用SQLite Asset Helper库来处理设置和升级应用数据库的肮脏工作。它工作得非常好但不幸的是我还没有找到一种方法来通知用户库:
A)首次加载数据库(通过从\ assets \ databases \文件夹解压缩)
或
B)升级数据库(使用\ assets \ datates中升级的数据库文件中的信息)
我尝试将此代码放在我的应用程序的主Activity.onCreate()中,以为我可以在主线程上加载数据库(如果它不存在),同时使用不可忽略的AlertDialog分散用户的注意力:< / p>
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();
}
不幸的是(基于LogCat条目),SQLite资产助手会在onCreate()之前检查数据库是否存在,所以当上面的代码块运行时,数据库已经存在,因此对话框永远不会出现
我正在使用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库仍然可以在我通知用户之前很好地加载数据库
在这种情况下,我可以做什么来拦截数据库的初始设置或升级,并通知用户应用程序正在忙于执行这些任务?现在,应用程序只是在那里做任何事情,直到库完成 - 这对测试很好,因为我知道期待它,但是当我准备让应用程序上线时,我不能这样做。
答案 0 :(得分:6)
万一你仍然想知道这个或其他人有这个问题,这里是我刚刚实施的类似问题的解决方案。在调用getReadableDatabase()或getWritableDatabase()之前,SQLiteAssetHelper不会复制数据库。如果在MainActivity.onCreate()之前调用其中一个方法,可能是因为您在ContentProvider的onCreate()方法中调用它。以下是documentation:
中的方法说明实施此操作以初始化您的内容 启动时的提供商。对所有已注册的内容调用此方法 应用程序启动时应用程序主线程上的提供程序。 它不能执行冗长的操作,或者应用程序启动 延迟。
你应该推迟非常重要的初始化(比如打开, 升级和扫描数据库),直到使用内容提供程序 (通过查询(Uri,String [],String,String [],String),插入(Uri, ContentValues)等)。延迟初始化保持应用程序 快速启动,如果提供商拒绝,则避免不必要的工作 需要,并从中停止数据库错误(如完整磁盘) 停止申请发布。
如果使用SQLite,SQLiteOpenHelper是一个有用的实用程序类 使数据库管理变得容易,并将自动推迟 开放直到第一次使用。如果你确实使用SQLiteOpenHelper,请确保 避免从中调用getReadableDatabase()或getWritableDatabase() 方法。 (而是覆盖onOpen(SQLiteDatabase)来初始化 数据库首次打开时。)
如实际访问ContentProvider,您可以调用getReadableDatabase()或getWritableDatabase(),如here所述。
既然您的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);
}
// ...
}
答案 1 :(得分:2)
源代码告诉我,AssetHelper正确地继承自SqliteOpenHelper。在没有任何代码或logcat查看的情况下,在主要Activity的onCreate之前创建数据库的唯一理智之处是某些类静态初始化(如果您没有使用Application对象)。检查一下。
至于通知:当数据未准备好并且使用装载程序时使用EmptyView占位符,因为:
它们不会阻止用户界面:用户可以在EmptyView中看到数据已被处理,甚至可以暂停活动。
他们不会因破坏活动而死亡,可以重复使用。
他们是标准的。