我应该如何通知用户SQLite Asset Helper第一次加载数据库?

时间:2013-05-23 18:37:45

标签: android android-sqlite

我正在使用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库仍然可以在我通知用户之前很好地加载数据库

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

2 个答案:

答案 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占位符,因为:

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

  2. 他们不会因破坏活动而死亡,可以重复使用。

  3. 他们是标准的。