我应该如何通知用户 SQLite Asset Helper 第一次加载数据库?
Posted
技术标签:
【中文标题】我应该如何通知用户 SQLite Asset Helper 第一次加载数据库?【英文标题】:How should I notify the user that SQLite Asset Helper is loading the database for the first time? 【发布时间】:2013-05-23 18:37:45 【问题描述】:我正在使用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 库仍然会在我通知用户之前加载数据库.
在这种情况下,我可以做些什么来拦截数据库的初始设置或升级并通知用户应用程序正忙于执行这些任务?现在,该应用程序在库完成之前什么都不做 - 这对于测试来说很好,因为我知道可以期待它,但是当我准备好让应用程序上线时,我不能就这样离开它。
【问题讨论】:
【参考方案1】:以防万一您仍然对此感到疑惑或其他任何人有此问题,这里有一个我刚刚实施的类似问题的解决方案。 SQLiteAssetHelper 在调用 getReadableDatabase() 或 getWritableDatabase() 之前不会复制数据库。如果在 MainActivity.onCreate() 之前调用了其中一种方法,则可能是因为您在 ContentProvider 的 onCreate() 方法中调用了它。这是来自documentation的方法描述:
执行此操作以初始化您的内容 启动时提供程序。为所有注册的内容调用此方法 应用程序启动时应用程序主线程上的提供程序。 它不能执行冗长的操作,否则应用程序启动将 延迟。
您应该推迟重要的初始化(例如打开, 升级和扫描数据库),直到使用内容提供程序 (通过查询(Uri,String[],String,String[],String),插入(Uri, 内容值)等)。延迟初始化保持应用程序 快速启动,如果提供商不这样做,可以避免不必要的工作 需要,并停止数据库错误(例如磁盘已满) 停止应用程序启动。
如果您使用 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);
// ...
【讨论】:
我完全忘记了这个问题,但你说得对!我遵循了与您上面描述的类似的路径:我推迟对数据库的任何调用,直到用户启动搜索,从而允许我在我的主 Activity 的OnCreate()
上检查数据库是否存在。如果数据库不存在,那么我将启动一个单独的 Activity,专门用于处理重新下载任何丢失的 OBB 并从该文件实例化 SQLite 数据库 - 用户会通过不可关闭的 DialogFragment 收到通知。
对此的快速补充:我尝试在一个活动中使用此方法时遇到了严重的崩溃,该活动填充了ListView
,并将数据库的内容加载到AsyncTask
中。在这种情况下,您最好使用EmptyView
,正如@alexeiburmistrov 在他的回答中所建议的那样。【参考方案2】:
源代码告诉我们,AssetHelper 正确地继承自 SqliteOpenHelper。无需查看任何代码或 logcat,在主 Activity 的 onCreate 之前可以创建数据库的唯一合理的地方是 一些类静态初始化(如果您不使用 Application 对象)。检查一下。
关于通知:当数据未准备好时使用 EmptyView 占位符并使用 Loaders,因为:
它们不会阻塞用户界面:用户可以在 EmptyView 中看到数据已被处理,甚至可以暂时离开活动。
它们不会在 Activity 销毁时死亡,并且可以重复使用。
它们是标准的。
【讨论】:
以上是关于我应该如何通知用户 SQLite Asset Helper 第一次加载数据库?的主要内容,如果未能解决你的问题,请参考以下文章