Android.Database.Sqlite.Sqlitecantopendatabaseexception: Unknown Error (Code 14): Could Not Open Database

SQLiteCantOpenDatabaseException: unknown error (code 14 SQLITE_CANTOPEN): Could not open database

Considering the comment

I am trying to create a database. How can use disableWriteAheadLogging
before creating a database? –

Then I believe that your issue is that you haven't granted the required permissions even though you say you have as per :-

Added both read and write permissions.

You need to grant WRITE_EXTERNAL_STORAGE (this implicitly grants READ_EXTERNAL_STORAGE).

For devices API 23+ Android 6+ rather than 9+ this requires permissions to be granted via the MANIFEST e.g. :-

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

But also that the user grant access as per Permission approval. For devices less then API 23 only the manifest permission is required.

Example

The following is a simple example that boh replicates the issue and shows that granting the permissions corrects the issue.

  • The manifest contains the above uses-permission entry.

The user permission is reuested via the following (ExternalStoragePermissions.java) :-

abstract class ExternalStoragePermissions {

private static final int REQUEST_EXTERNAL_STORAGE = 1;
private static String[] PERMISSIONS_STORAGE = {
Manifest.permission.WRITE_EXTERNAL_STORAGE
};

public ExternalStoragePermissions(Activity callingActivity) {}
// Note call this method
public static void verifyStoragePermissions(Activity activity) {
int permission = ActivityCompat.checkSelfPermission(
activity,
Manifest.permission.WRITE_EXTERNAL_STORAGE);

if(permission != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(
activity,
PERMISSIONS_STORAGE,
REQUEST_EXTERNAL_STORAGE
);
}
}
}

The activity (MainActivity.java) used is :-

public class MainActivity extends AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

if(Build.VERSION.SDK_INT >= 23) {
ExternalStoragePermissions.verifyStoragePermissions(this);
}

SQLiteDatabase myDB = null;
myDB = this.openOrCreateDatabase("/sdcard/Download/2019-11-14 07-49-56 AM.db", MODE_PRIVATE, null);
DatabaseUtils.dumpCursor(
myDB.query("sqlite_master",null,null,null,null,null,null)
);
myDB.close();
}
}

Results

When run for the first time the App displays :-

Sample Image

However as the main thread continues and access hasn't been granted then the log includes :-

2019-11-15 08:35:33.439 11874-11874/a.so58855993copyfromassets D/AndroidRuntime: Shutting down VM
2019-11-15 08:35:33.440 11874-11874/a.so58855993copyfromassets E/AndroidRuntime: FATAL EXCEPTION: main
Process: a.so58855993copyfromassets, PID: 11874
java.lang.RuntimeException: Unable to start activity ComponentInfo{a.so58855993copyfromassets/a.so58855993copyfromassets.MainActivity}: android.database.sqlite.SQLiteCantOpenDatabaseException: unknown error (code 14 SQLITE_CANTOPEN): Could not open database
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3270)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3409)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:83)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2016)
at android.os.Handler.dispatchMessage(Handler.java:107)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7356)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
Caused by: android.database.sqlite.SQLiteCantOpenDatabaseException: unknown error (code 14 SQLITE_CANTOPEN): Could not open database
at android.database.sqlite.SQLiteConnection.nativeOpen(Native Method)
at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:215)
at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:197)
at android.database.sqlite.SQLiteConnectionPool.openConnectionLocked(SQLiteConnectionPool.java:505)
at android.database.sqlite.SQLiteConnectionPool.open(SQLiteConnectionPool.java:206)
at android.database.sqlite.SQLiteConnectionPool.open(SQLiteConnectionPool.java:198)
at android.database.sqlite.SQLiteDatabase.openInner(SQLiteDatabase.java:915)
at android.database.sqlite.SQLiteDatabase.open(SQLiteDatabase.java:895)
at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:786)
at android.app.ContextImpl.openOrCreateDatabase(ContextImpl.java:812)
at android.app.ContextImpl.openOrCreateDatabase(ContextImpl.java:797)
at android.content.ContextWrapper.openOrCreateDatabase(ContextWrapper.java:310)
at a.so58855993copyfromassets.MainActivity.onCreate(MainActivity.java:27)
at android.app.Activity.performCreate(Activity.java:7802)
at android.app.Activity.performCreate(Activity.java:7791)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1299)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3245)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3409) 
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:83) 
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135) 
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95) 
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2016) 
at android.os.Handler.dispatchMessage(Handler.java:107) 
at android.os.Looper.loop(Looper.java:214) 
at android.app.ActivityThread.main(ActivityThread.java:7356) 
at java.lang.reflect.Method.invoke(Native Method) 
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492) 
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930) 

However at this stage the App remains active as the dialog requesting permission is still active. Clicking Allow result in the App crashing but then restarting and successfully creating the database as per the log containig :-

2019-11-15 08:41:13.615 I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor@5df21a1
2019-11-15 08:41:13.616 I/System.out: 0 {
2019-11-15 08:41:13.616 I/System.out: type=table
2019-11-15 08:41:13.616 I/System.out: name=android_metadata
2019-11-15 08:41:13.616 I/System.out: tbl_name=android_metadata
2019-11-15 08:41:13.616 I/System.out: rootpage=3
2019-11-15 08:41:13.616 I/System.out: sql=CREATE TABLE android_metadata (locale TEXT)
2019-11-15 08:41:13.616 I/System.out: }
2019-11-15 08:41:13.616 I/System.out: <<<<<
  • Note the above is only a demonstration. In an App to be used you would obviously set the permissions before attempting to access the database.
  • Ideally you should not hard code paths but use the system values e.g. Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) for the path.
  • Typically you would place Databases in the App's data via the Context's getDatabasePath method rather than place the dataset in the downloads folder.

    • Permission for the standard location in the App's data is granted and thus does not need to be requested.

android.database.sqlite.SQLiteCantOpenDatabaseException: unknown error (code 14): Could not open database still unable to fix issue

Issue: Most of the times SQLiteCantOpenDatabaseException occurs when you are access your sqlite database from multiple threads. Let say you have opened the database in one thread and trying to access the database in another will cause SQLiteCantOpenDatabaseException exception.

Solution: Make a singleton object of your SQLiteOpenHelper class and always use the same instance for multiple threads.

Sample:

DBHelper class:

public class DBHelper extends SQLiteOpenHelper {
private DBHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}

public synchronized static DBHelper getInstance(Context context) {
if (dbHelper == null) {
dbHelper = new DBHelper(context);
}

return dbHelper;
}

@Override
public void onCreate(SQLiteDatabase sqLiteDatabase) {
//...
}

@Override
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {
//...
onCreate(sqLiteDatabase);
}
}

Usage:

private static SQLiteDatabase database;


DBHelper dbHelper = DBHelper.getInstance(context);
if (database == null) {
database = dbHelper.getWritableDatabase();
}

Note: Never close the SqliteDatabase instance yourself android system does it for you.

SQLiteCantOpenDatabaseException: unknown error (code 14) Could not open database

Error stopped to show after I changed the targetSdkVersion from 23 to 22.
This downgrade forced to uninstall the package at the device and when It was reinstalled it worked fine. Thank you Frank N. Stein for the help!

.SQLiteCantOpenDatabaseException: unknown error (code 14): Could not open database

You are never opening the db referenced in your DBHelper.isPreviousDataExist() method. It is referencing the global, static db:

DBHelper.java

public static SQLiteDatabase db

You can either make it an instance variable and initialise it in the constructor (preferred) or get rid it of it altogether and create a local SQLiteDatabase in your DBHelper.isPreviousDataExist() method, like you have done in the other methods.

Lastly, there are various things wrong with your code but a public static member is a big code smell. See this for why.

android.database.sqlite.SQLiteCantOpenDatabaseException: unknown error (code 14): Could not open database trouble

You are using SQLiteDatabase.openDatabase on a file path that may not exist. Add below 2 lines just before SQLiteDatabase.openDatabase call

File file = new File(myPath);    
if (file.exists() && !file.isDirectory())

unknown error (code 14): Could not open database when writing externally in android

Check these points

1.READ_EXTERNAL_STORAGE and WRITE_EXTERNAL_STORAGE are defined in androidmanifest.xml

2.External storage Directory is created.If not, the before invoking constructor of db Helper create storage directory

Try this code of dbHelper

public class DbHelper extends SQLiteOpenHelper {

private static final String TABLE_MENU_LOCAL = "menu";
private static final String KEY_MENUID_LOCAL ="menuid" ;
private static final String KEY_MENUNAME_LOCAL ="menuname" ;
private static final String KEY_ISCHILD_LOCAL ="ischild" ;
private static final String KEY_CATEGORYURL_LOCAL ="categoryurl" ;
private static final String KEY_IMAGEID_LOCAL ="imageid" ;
private static final String KEY_MENUNAME_DESCRIPTION_LOCAL ="description" ;

private static String DATABASE_NAME="dbtest.db";
private static int DATABASE_VERSION=1;

public DbHelper(Context context)
{
// code to create database in internal storage
//super(context, DATABASE_NAME, null, DATABASE_VERSION);

//code to create database in External SD card


super(context, Environment.getExternalStorageDirectory()
+ File.separator + "/myapp/db/"
+ File.separator
+ DATABASE_NAME, null, DATABASE_VERSION);

}

@Override
public void onCreate(SQLiteDatabase db) {
//1
String CREATE_TABLE_MENU = "CREATE TABLE IF NOT EXISTS " + TABLE_MENU_LOCAL +"("
+KEY_MENUID_LOCAL + " TEXT,"
+KEY_MENUNAME_LOCAL + " TEXT,"
+KEY_ISCHILD_LOCAL + " TEXT,"
+KEY_CATEGORYURL_LOCAL + " TEXT,"
+KEY_IMAGEID_LOCAL + " TEXT,"
+KEY_MENUNAME_DESCRIPTION_LOCAL + " TEXT"
+ ")";

db.execSQL(CREATE_TABLE_MENU);
}

@Override
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {

}

public void insertValues(){
SQLiteDatabase db=this.getWritableDatabase();

for(int count=0;count<5;count++) {
ContentValues insertValues = new ContentValues();
insertValues.put(KEY_MENUID_LOCAL, "1");
insertValues.put(KEY_MENUNAME_LOCAL, "Food1");
insertValues.put(KEY_ISCHILD_LOCAL, "No");
insertValues.put(KEY_CATEGORYURL_LOCAL, "Demo");
insertValues.put(KEY_IMAGEID_LOCAL, "imageid");
insertValues.put(KEY_MENUNAME_DESCRIPTION_LOCAL, "Description");
db.insert(TABLE_MENU_LOCAL, null, insertValues);
}
}

//to get totalcount
public int getCountValueForMainMenu()
{
SQLiteDatabase db = this.getWritableDatabase();
int count = 0;
Cursor cursor = db.rawQuery("SELECT COUNT (*) FROM " + TABLE_MENU_LOCAL, null);

if(null != cursor)
{
if(cursor.moveToFirst() && 0 < cursor.getCount())
{
count = cursor.getInt(0);
}

cursor.close();
}

return count;
}

}

and invoke this from your activity or anywhere like this

 String storage_folder = "/myapp/db";

File f = new File(Environment.getExternalStorageDirectory(), storage_folder);
if (!f.exists()) {
f.mkdirs();
}
DbHelper lDbHeper=new DbHelper(MainActivity.this);
lDbHeper.insertValues();
int count=lDbHeper.getCountValueForMainMenu();

Log.i("Count is:",""+count);

let me know it helps you or not



Related Topics



Leave a reply



Submit