我有一个应用程序,它获取一个压缩的sqlite数据库转储文件并使用该数据库。 I used this tutorial as a guide on how to fetch the database.但是,出于我的目的,我改为在我的localhost(192.168.1.4)上托管了一个数据库。
上面的链接还包含我为了参考目的而下载的完整项目,但是我必须以这样的方式调整代码,即它使用AsyncTask来获取数据库,否则我会得到一个NetworkOnMainThreadException。我设法使AsyncTask正常工作,我的AsyncTask看起来像这样:
private class Connection extends AsyncTask {
@Override
protected Object doInBackground(Object... arg0) {
//connect();
myDroidSQLDatabase = new MyDroidSQLDatabase(MyDBAppActivity.this);
myDroidSQLDatabase.open();
return null;
}
}
在我的主要活动中调用它如下:
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
new Connection().execute();
}
问题似乎在onResume()中,因为logcat显示错误无法恢复活动:
@Override
protected void onResume() {
myDroidSQLDatabase.open();
super.onResume();
}
我不太清楚为什么在我第一次在我的设备上安装应用程序时触发了onResume()。我认为问题是在onCreate()之后,onResume()被调用,并且由于数据库仍处于打开状态,它正在尝试打开已打开的db。
但是,网站上的原始示例在应用程序中部署打包的转储文件并正确执行。由于此方法不需要db提取并在AsyncTask中执行,因此onResume不起作用。所以我现在的猜测是我必须等待AsyncTask完成,以便onResume()不会给我带来问题。
很抱歉,我对线程和异步任务完全不熟悉,所以我不知道如何在完成工作时处理线程。我认为问题是onResume尝试运行(作为活动生命周期的一部分),并且由于Async Task尚未完成,open()调用会起作用。
有什么想法吗?
此外,这里还有三个类,它可能有所帮助。 MyDroidSQLDatabase
public class MyDroidSQLDatabase {
private SQLiteOpenHelper sqlLiteOpenHelper;
private SQLiteDatabase sqlLiteDatabase;
public MyDroidSQLDatabase(Context context) {
sqlLiteOpenHelper = new MyDroidSQLiteOpenHelper(context);
}
public void open() {
sqlLiteDatabase = sqlLiteOpenHelper.getWritableDatabase();
}
public void close() {
sqlLiteDatabase.close();
}
public SQLiteDatabase getSqlLiteDatabase() {
return sqlLiteDatabase;
}
}
MyDroidSQLiteOpenHelper
public class MyDroidSQLiteOpenHelper extends SQLiteOpenHelper {
private Context context;
private static final String __DB_NAME = "mydbapp.db";
private static final int __DB_VERSION = 1;
public MyDroidSQLiteOpenHelper(Context context) {
super(context, __DB_NAME, null, __DB_VERSION);
this.context=context;
}
@Override
public void onCreate(SQLiteDatabase sqlLiteDb) {
try {
//SQLiteDBDeploy.deploy(sqlLiteDb, this.context, "northwind.zip");
// if you like to download file from remote site comment above line and uncomment below line.
SQLiteDBDeploy.deploy(sqlLiteDb,
//"http://ingenious-camel.googlecode.com/svn/trunk/SQLiteDBDeployer/assets/northwind.zip");
"http://192.168.1.4/dbtest/android.zip");
} catch (IOException e) {
Log.e(MyDBAppActivity.TAG,e.getMessage(),e);
throw new Error(e.getMessage());
}
}
@Override
public void onUpgrade(SQLiteDatabase sqlLiteDb, int oldVersion, int newVersion) {
}
}
SQLiteDBDeploy
public class SQLiteDBDeploy {
private static final String TAG = "SQLiteDBDeploy";
private static List<String> ignoreSQLs;
static {
ignoreSQLs = new LinkedList<String>();
ignoreSQLs.add("--");
ignoreSQLs.add("begin transaction;");
ignoreSQLs.add("commit;");
ignoreSQLs.add("create table android_metadata (locale text);");
ignoreSQLs.add("create table \"android_metadata\" (locale text);");
ignoreSQLs.add("insert into android_metadata values('en_us');");
ignoreSQLs.add("insert into \"android_metadata\" values('en_us');");
}
/**
* Deploys given zip file in SQLiteDatabase
*
* @param sqlLiteDb
* the database
* @param context
* to use to open or create the database
* @param dbName
* dump zip file
* @throws IOException
*/
public static void deploy(SQLiteDatabase sqlLiteDb, Context context, String dbName) throws IOException {
Log.i(TAG, "reading zip file: " + dbName);
InputStream dbStream = context.getAssets().open(dbName);
deploy(sqlLiteDb, dbStream);
dbStream.close();
}
/**
* Deploys given zip file url in SQLiteDatabase
*
* @param sqlLiteDb
* the database
* @param dbUrl
* dump zip file url
* @throws IOException
*/
public static void deploy(SQLiteDatabase sqlLiteDb, String dbUrl) throws IOException {
Log.i(TAG, "reading url: " + dbUrl);
HttpURLConnection c = (HttpURLConnection) new URL(dbUrl).openConnection();
c.setRequestMethod("GET");
c.setDoOutput(true);
c.connect();
InputStream dbStream = c.getInputStream();
deploy(sqlLiteDb, dbStream);
dbStream.close();
c.disconnect();
}
/**
* Deploys given dump file stream in SQLiteDatabase
*
* @param sqlLiteDb the database
* @param dbStream stream to read dump data
* @throws IOException
*/
private static void deploy(SQLiteDatabase sqlLiteDb, InputStream dbStream) throws IOException {
ZipInputStream zis = new ZipInputStream(new BufferedInputStream(dbStream));
ZipEntry entry = null;
while ((entry = zis.getNextEntry()) != null) {
Log.i(TAG, "deploying zip entry: " + entry);
InputStreamReader dbReader = new InputStreamReader(zis);
deploy(sqlLiteDb, dbReader);
}
}
/**
* Deploys given stream in SQLiteDatabase
*
* @param sqlLiteDb
* the database
* @param dbReader
* stream to read dump SQL statements
* @throws IOException
* @throws SQLException
*/
private static void deploy(SQLiteDatabase sqlLiteDb, InputStreamReader dbReader) throws IOException {
String sqlLine = null;
StringBuffer sqlBuffer = new StringBuffer();
BufferedReader bufferedReader = new BufferedReader(dbReader);
sqlLiteDb.beginTransaction();
try {
while ((sqlLine = bufferedReader.readLine()) != null) {
String sql = sqlLine.trim();
if (!isIgnoreSQL(sql)) {
if (sql.endsWith(";")) {
sqlBuffer.append(sql);
String execSQL = sqlBuffer.toString();
Log.d(TAG, "running sql=>" + execSQL);
sqlLiteDb.execSQL(execSQL);
sqlBuffer.delete(0, sqlBuffer.length());
} else {
if (sqlBuffer.length() > 0) {
sqlBuffer.append(' ');
}
sqlBuffer.append(sql);
}
}
}
sqlLiteDb.setTransactionSuccessful();
} finally {
sqlLiteDb.endTransaction();
}
}
/**
* Returns true if the given SQL statement is to be ignored
* @param sql SQL statement
* @return
*/
private static boolean isIgnoreSQL(String sql) {
if (sql.length() == 0) {
return true;
}
String lowerSQL = sql.toLowerCase();
for (String ignoreSQL : ignoreSQLs) {
if (lowerSQL.startsWith(ignoreSQL)) {
return true;
}
}
return false;
}
}
答案 0 :(得分:1)
我不太确定为什么在我第一次在我的设备上安装应用程序时会触发onResume()。
首次创建onResume()
时始终会调用Activity
方法 - 而不仅仅是Activity
暂停时。见Activity Lifecycle
我认为问题是在onCreate()之后调用onResume()并且由于数据库仍处于打开状态,因此它正在尝试打开已打开的数据库。
不,那不应该。允许多次调用getWriteableDatabase()
。
您收到错误的最可能原因是AsyncTask
doInBackground(...)
方法尚未完成。这是AsyncTask
的重点 - 它是异步的,并且execute()
方法中对onCreate(...)
的调用将立即返回。您应该使用onPostExecute(...)
的{{1}}方法。