android


SQLite disk IO exception and can't open database exception


I have gone through other similar questions but I did not get an answer.
In my android app I'm opening a pre-built database. It is in the assets folder and copied using SQLiteOpenHelper, if not already present. This the class:
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import android.content.Context;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
public class ExternalDbOpenHelper extends SQLiteOpenHelper {
public static String DB_PATH;
public static String DB_NAME;
public SQLiteDatabase database;
public final Context context;
public SQLiteDatabase getDb() {
return database;
}
public ExternalDbOpenHelper(Context context, String databaseName) {
super(context, databaseName, null, 1);
this.context = context;
String packageName = context.getPackageName();
DB_PATH = String.format("//data//data//%s//databases//", packageName);
DB_NAME = databaseName;
openDataBase();
}
public void createDataBase() {
boolean dbExist = checkDataBase();
if (!dbExist) {
this.getReadableDatabase();
try {
copyDataBase();
} catch (IOException e) {
// Log.e(this.getClass().toString(), "Copying error");
//throw new Error("Error copying database!");
}
} else {
// Log.i(this.getClass().toString(), "Database already exists");
}
}
private boolean checkDataBase() {
SQLiteDatabase checkDb = null;
try {
String path = DB_PATH + DB_NAME;
checkDb = SQLiteDatabase.openDatabase(path, null,
SQLiteDatabase.OPEN_READONLY);
} catch (SQLException e) {
// Log.e(this.getClass().toString(), "Error while checking db");
}
if (checkDb != null) {
checkDb.close();
}
return checkDb != null;
}
private void copyDataBase() throws IOException {
InputStream externalDbStream = context.getAssets().open(DB_NAME);
String outFileName = DB_PATH + DB_NAME;
OutputStream localDbStream = new FileOutputStream(outFileName);
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = externalDbStream.read(buffer)) > 0) {
localDbStream.write(buffer, 0, bytesRead);
}
localDbStream.close();
externalDbStream.close();
}
public SQLiteDatabase openDataBase() throws SQLException {
String path = DB_PATH + DB_NAME;
if (database == null) {
createDataBase();
database = SQLiteDatabase.openDatabase(path, null,
SQLiteDatabase.OPEN_READWRITE); //caused by this line
}
return database;
}
#Override
public synchronized void close() {
if (database != null) {
database.close();
}
super.close();
}
#Override
public void onCreate(SQLiteDatabase db) {
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
And this is in my activity:
private static final String DB_NAME = "myDB.sqlite";
private SQLiteDatabase database;
private ExternalDbOpenHelper dbOpenHelper;
//in onCreate()
dbOpenHelper = new ExternalDbOpenHelper(this,DB_NAME);
database = dbOpenHelper.openDataBase();
In my app I repeatedly query the database using a cursor and rawQuery. I open the database OPEN_READONLY as I never modify it. So so wasn't closing it before. Added this now:
#Override
protected void onDestroy()
{
dbOpenHelper.close();
super.onDestroy();
}
Was this the problem? I had never experienced SQLite disk IO exception and can't open database exception before(without dbOpenHelper.close();. It was reported once each in crash report). Both times apps crashed on launch and was caused by the line
database = SQLiteDatabase.openDatabase(path, null, SQLiteDatabase.OPEN_READWRITE);
in openDataBase() in theExternalDbOpenHelper class.
I'm unable to reproduce the errors. The two devices that reported it have device names as "Other" and blank.
android.database.sqlite.SQLiteCantOpenDatabaseException
in android.database.sqlite.SQLiteDatabase.dbopen:
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.technicosa.unjumble/com.technicosa.unjumble.MainActivity}: android.database.sqlite.SQLiteCantOpenDatabaseException: unable to open database file
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1956)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1981)
at android.app.ActivityThread.access$600(ActivityThread.java:123)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1147)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4424)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
at dalvik.system.NativeStart.main(Native Method)
Caused by: android.database.sqlite.SQLiteCantOpenDatabaseException: unable to open database file
at android.database.sqlite.SQLiteDatabase.dbopen(Native Method)
at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:1013)
at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:986)
at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:1024)
at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:986)
at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:962)
at com.technicosa.unjumble.dbhelper.ExternalDbOpenHelper.openDataBase(ExternalDbOpenHelper.java:90)
at com.technicosa.unjumble.dbhelper.ExternalDbOpenHelper.<init>(ExternalDbOpenHelper.java:33)
at com.technicosa.unjumble.MainActivity.onCreate(MainActivity.java:131)
at android.app.Activity.performCreate(Activity.java:4465)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1049)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1920)
... 11 more
Look at This this is working like a charm
public class SmartOpenHelper extends SQLiteOpenHelper {
private Context context;
private SQLiteDatabase myDataBase;
private String DB_SQL;
private SmartVersionHandler smartVersionHandler;
SmartOpenHelper(Context context, String dbname, int dbversion, String dbSqlName, SmartVersionHandler smartVersionHandler) throws IOException {
super(context, dbname, null, dbversion);
this.context = context;
this.DB_SQL = dbSqlName;
this.smartVersionHandler = smartVersionHandler;
}
#Override
public void onCreate(SQLiteDatabase db) {
try {
BufferedInputStream inStream = new BufferedInputStream(context.getAssets().open(DB_SQL));
String sql = "";
int character = -2;
do {
character = inStream.read();
if ((character != -1) && (character != -2))
sql += (char) character;
else
break;
} while (true);
System.out.println("onCreate DB SQL = " + sql.split("\n"));
String[] arrSQL = sql.split("\n");
for (int i = 0; i < arrSQL.length; i++) {
db.execSQL(arrSQL[i]);
}
} catch (IOException e) {
e.printStackTrace();
}
if (this.smartVersionHandler != null) {
this.smartVersionHandler.onInstalling(SmartApplication.REF_SMART_APPLICATION);
}
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
try {
BufferedInputStream inStream = new BufferedInputStream(context.getAssets().open(DB_SQL));
String sql = "";
int character = -2;
do {
character = inStream.read();
if ((character != -1) && (character != -2))
sql += (char) character;
else
break;
} while (true);
System.out.println("onUpgrade DB SQL = " + sql.split("\n"));
String[] arrSQL = sql.split("\n");
for (int i = 0; i < arrSQL.length; i++) {
db.execSQL(arrSQL[i]);
}
} catch (IOException e) {
e.printStackTrace();
}
if (this.smartVersionHandler != null) {
this.smartVersionHandler.onUpgrading(oldVersion, newVersion, SmartApplication.REF_SMART_APPLICATION);
}
}
public SQLiteDatabase getOpenDatabase() {
return myDataBase;
}
public synchronized void close() {
if (myDataBase != null) {
myDataBase.close();
}
super.close();
}
}
I don't really think this is a good approach to the problem. SQLiteOpenHelper it's not meant to be used like that. You should copy the DB outside the helper class and then initialize the helper which should serve you only to get the SQLiteDatabase (through getReadableDatabase and/or getWritableDatabase).
However, reading the code I don't see why you call getReadableDatabase before copyDataBase in createDataBase function. You should also check the database path as hotveryspicy suggests.
Can you please post the stack trace of the exception?
Try with this edits:
public class ExternalDbOpenHelper extends SQLiteOpenHelper {
public static String DB_PATH;
public static String DB_NAME;
public SQLiteDatabase database;
public final Context context;
public SQLiteDatabase getDb() {
return database;
}
public ExternalDbOpenHelper(Context context, String databaseName) {
super(context, databaseName, null, 1);
this.context = context;
String packageName = context.getPackageName();
DB_PATH = String.format("%s//data//%s//databases//", Environment.getDataDirectory(), packageName); // as per hotveryspicy comment
DB_NAME = databaseName;
openDataBase();
}
public void createDataBase() {
boolean dbExist = checkDataBase();
if (!dbExist) {
//this.getReadableDatabase(); why do you call getReadableDatabase() here?
try {
copyDataBase();
} catch (IOException e) {
// Log.e(this.getClass().toString(), "Copying error");
//throw new Error("Error copying database!");
}
} else {
// Log.i(this.getClass().toString(), "Database already exists");
}
}
private boolean checkDataBase() {
SQLiteDatabase checkDb = null;
try {
String path = DB_PATH + DB_NAME;
checkDb = SQLiteDatabase.openDatabase(path, null,
SQLiteDatabase.OPEN_READONLY);
} catch (SQLException e) {
// Log.e(this.getClass().toString(), "Error while checking db");
}
if (checkDb != null) {
checkDb.close();
}
return checkDb != null;
}
private void copyDataBase() throws IOException {
InputStream externalDbStream = context.getAssets().open(DB_NAME);
String outFileName = DB_PATH + DB_NAME;
OutputStream localDbStream = new FileOutputStream(outFileName);
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = externalDbStream.read(buffer)) > 0) {
localDbStream.write(buffer, 0, bytesRead);
}
localDbStream.close();
externalDbStream.close();
}
public SQLiteDatabase openDataBase() throws SQLException {
String path = DB_PATH + DB_NAME;
if (database == null) {
createDataBase();
//database = SQLiteDatabase.openDatabase(path, null,
//SQLiteDatabase.OPEN_READWRITE);
database = getWritableDatabase(); // <- try with this
}
return database;
}
#Override
public synchronized void close() {
if (database != null) {
database.close();
}
super.close();
}
#Override
public void onCreate(SQLiteDatabase db) {
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}

Related Links

How to append multiple ImageSpans on an EditText?
Change displayname in firebase don't work
Espresso UI test on Android Floating Action Button menu items
How to write an IPERF Android application
Android: app startup stuck on black screen
Cordova/Ionic 2: Force camera aspect ratio Android/iOS
Error building app with importet .jar file
How do I get the file path from the content URI for video files?
Background view needs to be small when I drag top view in android
How many Users can connect through the One MongoDB C++ driver?
input:checked ~ div.submenu Android browser 4.4.2
Android webview shows “open this website in chrome or mozilla”
Android Firebase & Play Services library conflicts
Android studio NavigationDrawer sub items that change on runtime
How to POST following data using retrofit
Some Kivy Buildozer related stuff I'm not sure about

Categories

HOME
sonarqube
grok
kentico
time-complexity
phpmyadmin
angular2-material
obfuscation
newrelic
cublas
settings
tvos
spring-session
data-visualization
bing-maps
opengl-es-3.0
intercom
scrolltop
internationalization
powershell-v5.0
imessage
windows-xp
guzzle
roslyn
fable-f#
google-earth
ntp
complex-numbers
kodi
r-grid
video-capture
google-knowledge-graph
health-monitoring
typesafe-config
datacachefactory
android-ibeacon
movilizer
sharp-snmp
drupal-theming
vaadin-elements
chai-as-promised
geotiff
reindex
qtranslate
flac
meteor-packages
segment-io
dimension
tracker-enabled-dbcontext
hadoop-partitioning
halcon
state-restoration
opl
jdk1.7
zend-currency
j-security-check
packet-sniffers
psr-4
gii
create.js
decoupling
windows-embedded-standard
visual-studio-express
eclipse-kepler
scrypt
inputmismatchexception
neos-server
cmmi
workitem
jquery-1.9
font-awesome-4.0.0
swfobject
pdfviewer
curb
monotouch.dialog
wcf-configuration
database-create
koken
promotion-code
cuteeditor
dataform
cdonts
non-clustered-index
build-environment
filesystemobject
wcf-instancing
dsl-tools
google-wave
interop-domino
fdf
entitykey

Resources

Encrypt Message