4

I've been struggling to create a SQLite DB within my Android application. I've looked at numerous tutorials, and quite a few existing questions on stack overflow and other sites.

Here is my DatabaseHelper class

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;

public class DatabaseHelper extends SQLiteOpenHelper {

public SQLiteDatabase db;
public static final String DATABASE_NAME = "user.db";

//Module table
public static final String MODULE_TABLE = "modules_table";
public static final String MODULE_COL_1 = "ID";
public static final String MODULE_COL_2 = "CODE";
public static final String MODULE_COL_3 = "TITLE";

public DatabaseHelper(Context context) {
    super(context, DATABASE_NAME, null, 1);
    Log.d("SQL", "SQLite dbhelper");
    db = getWritableDatabase();
}

@Override
public void onCreate(SQLiteDatabase db) {
    //db.execSQL("create table " + MODULE_TABLE + "(" + MODULE_COL_1 + " INTEGER PRIMARY KEY AUTOINCREMENT, " + MODULE_COL_2 + " TEXT, " + MODULE_COL_3 + " TEXT " +")");
    db.execSQL("create table modules_table (ID INTEGER PRIMARY KEY 
AUTOINCREMENT, CODE TEXT, TITLE TEXT)");
    Log.d("SQL", "SQLite onCreate");
}

@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    db.execSQL("DROP TABLE IF EXISTS " + MODULE_TABLE);
    onCreate(db);
}
}

I've managed to get SQLite dbhelper to appear in logcat, but cannot get SQLite onCreate to appear, and cannot find the db anywhere in the file explorer or the device itself, both emulated and real device.

Any help would be greatly appreciated, and apologies for the formatting of the code!

4
  • Never experienced this. If onCreate() is not called it's because the database already exists. It is under /data/data/your.app.package/databases, however you might not be able to browse those directories unless your phone is rooted. Commented Feb 8, 2019 at 19:15
  • Do you initialize a DatabaseHelper object anywhere in your code in any activity class? If not, then db = getWritableDatabase(); will never be called and the db will not be created. Commented Feb 8, 2019 at 19:18
  • @m0skit0 My phone is not rooted so that may be an issue, however upon checking through the virtual device file explorer the only sub folder I have within my package is the cache, which is also empty. Commented Feb 9, 2019 at 0:10
  • @forpas Yeah initializing it in my main activity, hence I am able to see the SQLite dbhelper log.d which I had added in. Commented Feb 9, 2019 at 0:11

2 Answers 2

2

I'd suggest using the following (temporarily) in the activity :-

DatabaseHelper myDBHelper = new DatabaseHelper(this); //<<<<<<<<< you appear to already have the equivalent of this line (if so use whatever variable name you have given to the DatabaseHelper object)

Cursor csr = myDBHelper.getWritableDatabase().query("sqlite_master",null,null,null,null,null,null);
DatabaseUtils.dumpCursor(csr);
csr.close();

Run and then check the log. You should see output for your modules_table and also sqlite_sequence (the latter because you have coded autoincrement.

sqlite_master is a system table that stores system information, such as table and index names i.e. the schema.

Additional - access to the database file

On a device that isn't rooted each applications data (data/data) is protected so you won't be able to see the database file.

On an emulator, it depends upon the emulator. I believe later versions of Android studio do now allow access e.g. :-

enter image description here

  • Note the above is Android 10.1 Pie (API 28) and hence the database has Write-Ahead Logging (WAL) and thus the -shm and -wal files also exist.

  • The package is mjt.pvcheck. The full path is data/data/mjt.pvcheck/databases.

    • As you can see cache directory, then I'd suggest that for some reason, perhaps a failure, the database doesn't exist, but you do appear to have access as per however upon checking through the virtual device file explorer the only sub folder I have within my package is the cache.
    • Perhaps, try rerunning on the device (note in device explorer re-select the device as it doesn't refresh), which may be another reason why you didn't see the database.
Sign up to request clarification or add additional context in comments.

4 Comments

I have implemented your suggestion and it seems to have returned the following in the log: Dumping cursor android.database.sqlite.SQLiteCursor@a2d630f sql=CREATE TABLE android_metadata (locale TEXT) sql=CREATE TABLE modules_table(ID INTEGER PRIMARY KEY AUTOINCREMENT, CODE TEXT, TITLE TEXT ) name=sqlite_sequence tbl_name=sqlite_sequence sql=CREATE TABLE sqlite_sequence(name,seq) I assume this means that the db is working as intended and the reason that onCreate() is not being called is because it already exists? Still very confused as to why I am unable to locate the db itself.
@ConnorC yes, as you can see the table(s) exist(s) as expected. On the real device the database is in a protected folder within the App's data (only accessible to the App unless device is rooted). Depends upon the emulator whether or not the db is accessible. Genymotion allows access, later Android Studio they are accessible. Main thing is yes the code is working as expected.
I'm still struggling to find a way to view the database file, do happen to know of any free emulators which allow access to protected folders and files? Cheers!
Sorted it using ADB within android studio and ensuring that my emulator was in debug mode.
1

I don't use SQL query like

db.execSQL("create table modules_table (ID INTEGER PRIMARY KEY 
AUTOINCREMENT, CODE TEXT, TITLE TEXT)");
    Log.d("SQL", "SQLite onCreate");

instead, I'm using my own implementation of SQLiteOpenHelper class

import android.content.Context;
import android.content.res.AssetManager;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.os.Environment;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.Log;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.zip.GZIPOutputStream;

public class DbProvider extends SQLiteOpenHelper {

    private static final ReentrantReadWriteLock LOCK = new ReentrantReadWriteLock(true);
    private static final int VERSION = 0;
    private final String DB_NAME = "mydb";

    private final AssetManager assets;

    private DbProvider(Context context) {
        super(context, DB_NAME, null, VERSION);
        assets = context.getAssets();
    }

    @NonNull
    public static DbProvider getInstance() {
        return new DbProvider(App.getContext());
    }

    @NonNull
    public static ReentrantReadWriteLock.WriteLock writeLock() {
        return LOCK.writeLock();
    }

    @NonNull
    public static ReentrantReadWriteLock.ReadLock readLock() {
        return LOCK.readLock();
    }

    @NonNull
    public static ReentrantReadWriteLock getLock() {
        return LOCK;
    }

    public static void close(DbProvider instance) {
        try {
            instance.close();
        } catch (Exception ex) {

        }
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        executeQuery(db, "db-scripts/database.sql", false);
        Log.w("database", "database create");
        executeQuery(db, "db-scripts/database_updates.sql", true);
        Log.w("database", "database update");
    }

    private void executeQuery(SQLiteDatabase db, String sql, boolean shouldHandleExceptions) {
        BufferedReader bufferedReader = null;
        try {
            bufferedReader = new BufferedReader(new InputStreamReader(assets.open(sql)));
            String line;
            File tempDbScript = new File(Environment.getExternalStorageDirectory(), "iErunt/dbBackup");
            tempDbScript.getParentFile().mkdirs();
            tempDbScript.createNewFile();
            BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(tempDbScript));
            while ((line = bufferedReader.readLine()) != null) {
                line = line.replaceAll("\t+", " ").replaceAll("\n+", " ").replaceAll(" +", " ").replaceAll(";", ";\n");
                if (line.startsWith("--") || line.isEmpty()) {
                    continue;
                }
                bufferedWriter.write(line);
                bufferedWriter.flush();
            }
            bufferedWriter.close();
            bufferedReader.close();
            bufferedReader = new BufferedReader(new FileReader(tempDbScript));
            db.beginTransaction();
            while ((line = bufferedReader.readLine()) != null) {
                if (!(line = line.trim().replace(";", "")).isEmpty()) {
                    if (shouldHandleExceptions) {
                        try {
                            db.execSQL(line);
                        } catch (SQLException ex) {
                            Log.e("database", ex.getMessage(), ex);
                        }
                    } else {
                        db.execSQL(line);
                    }
                }
            }
            db.setTransactionSuccessful();
            db.endTransaction();
            tempDbScript.delete();
        } catch (IOException ex) {
            Log.e("database", ex.getMessage(), ex);
        } finally {
            if (bufferedReader != null) {
                try {
                    bufferedReader.close();
                } catch (IOException e) {

                }
            }
        }
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        executeQuery(db, "db-scripts/database_updates.sql", true);
    }
}

and put initial DB schema of your database in assets/db-scripts/database.sql and whenever you make DB modifications put your alter queries in assets/db-scripts/database_updates.sql. Be sure to increase VERSION of the database when updating the database.

What this class does is read your entire SQL script and executes one by one. which significantly reduces development time.

Note: You'll need android.permission.WRITE_EXTERNAL_STORAGE permission, as this creates a temp file and deletes it at the end

Hope this helps!

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.