SQLiteDatabse giving NullPointerException - android

I am getting NullPointerException in the marked in the code.
The code typically reads a text file in raw folder in the project and inserts the contents in the table of the database. The text file in the raw folder contains a list of english words, for spell checking purpose. Could anyone help me regarding this matter.
public class WordsDB
{
private static final String FTS_WORD_DB="FTS_WORD_DB";
private static final String WORD="WORD";
private static final String FTS_WORD_DB_CREATE="CREATE VIRTUAL TABLE "+FTS_WORD_DB+" USING ft3 ("+WORD+");";
private static final String WORD_DATABASE="WORD_DATABSE";
private static final int DATABSE_VERSION=1;
private WordsDBLoadHelper helper;
public static SQLiteDatabase wordDb;
public WordsDB(Context context)
{
helper=new WordsDBLoadHelper(context);
}
public void load()
{
helper.loadWordDb();
}
public class WordsDBLoadHelper extends SQLiteOpenHelper
{
public WordsDBLoadHelper(Context context)
{
super(context, WORD_DATABASE, null, DATABSE_VERSION);
}
#Override
public void onCreate(SQLiteDatabase db)
{
wordDb=db;
wordDb.execSQL(FTS_WORD_DB_CREATE);
}
public void loadWordDb()
{
Resources resource=SearchDict.context.getResources();
InputStream is=resource.openRawResource(R.raw.wordlist);
BufferedReader br=new BufferedReader(new InputStreamReader(is));
String line;
try
{
while((line=br.readLine())!=null)
{
addWord(line.trim());
}
}
catch (Exception e)
{
Log.e(null, e.getStackTrace().toString(), e);
}
}
public void addWord(String line)
{
try
{
ContentValues values=new ContentValues();
values.put(WORD, line);
wordDb.insert(FTS_WORD_DB, null, values);
}
catch(Exception e)
{
Log.e(null, e.getStackTrace().toString(), e);
}
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
{
}
}
}
Is there any faster method to create table and insert values into it. The above procedure takes about more than a hour to insert values in the database because the text file contains more than 3 lakh words.
Is it possible to create the database once and store it permanently so that it is possible to retrieve values without recreating the database again and again when the project runs.

In Sqlite inserts are generally quite fast, but commits are slow. You're not using a transaction so after each insert sqlite does a commit.
wordDB.startTransaction();
try {
/*while loop*/
wordDB.setTransactionSuccessful();
} finally {
db.endTransaction();
}

Related

How to manually perform checkpoint in SQLite android?

I'm trying to create a backup of my sqlite database and I want to flush the content of the WAL file in the db first.
Here is my SQLiteOpenHelper:
public class MyDBHelper extends SQLiteOpenHelper {
private Context mContext;
private static MyDBHelper mInstance = null;
private MyDBHelper(final Context context, String databaseName) {
super(new MYDB(context), databaseName, null, DATABASE_VERSION);
this.mContext = context;
}
#Override
public void onCreate(SQLiteDatabase db) {
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
public static MyDBHelper getInstance(Context context) {
if (mInstance == null) {
mInstance = new MyDBHelper(context, DATABASE_NAME);
}
return mInstance;
}
private void closeDataBase(Context context) {
getInstance(context).close();
}
}
Now, my understanding is that after a checkpoint is completed, the mydb.db-wal file should be empty. Is that correct?
Here is what I've tried so far:
1.
public Completable flushWalInDB() {
return Completable.fromAction(new Action() {
#Override
public void run() throws Exception {
getInstance(mContext).getReadableDatabase().rawQuery("pragma wal_checkpoint;", null);
}
});
}
This doesn't throw an error but doesn't seem to do anything. After running this, I physically checked my mydb.db-wal file and had the same size. I also checked the db on the device and nothing was added in the database
After some digging around I found this
[https://stackoverflow.com/a/30278485/2610933][1]
and tried this:
2.
public Completable flushWalInDB() {
return Completable.fromAction(new Action() {
#Override
public void run() throws Exception {
getInstance(mContext).getReadableDatabase().execSQL("pragma wal_checkpoint;");
}
});
}
When running this it throws an error:
unknown error (code 0): Queries can be performed using SQLiteDatabase query or rawQuery methods only.
And based on this answer [https://stackoverflow.com/a/19574341/2610933][1] , I also tried to VACUUM the DB but nothing seems to happen.
public Completable vacuumDb() {
return Completable.fromAction(new Action() {
#Override
public void run() throws Exception {
getInstance(mContext).getReadableDatabase().execSQL("VACUUM");
}
});
}
}
Whats is the correct way of flushing the WAL file in the DB before creating a backup?
Thank you.
PRAGMA wal_checkpoint(2) does copy all data from the WAL into the actual database file, but it does not remove the -wal file, and any concurrent connections can make new changes right afterwards.
If you want to be really sure that there is no WAL to interfere with your backup, run PRAGMA journal_mode = DELETE. (You can switch it back afterwards.)
To manually add checkpont use PRAGMA wal_checkpoint, after searching for 2 hours following code worked for me -:
SQLiteDatabase db = this.getWritableDatabase();
String query = "PRAGMA wal_checkpoint(full)";
Cursor cursor = db.rawQuery(query, null);
if (cursor != null && cursor.moveToFirst()) {
int a = cursor.getInt(0);
int b = cursor.getInt(1);
int c = cursor.getInt(2);
}
if (cursor != null) {
cursor.close();
}

Creating database using orm

I am using ORMlite database for the first time in my application. i have taken reference from a tutorial, but instead of doing all the things exactly same i am not able to resolve an error. My code is below:-
DatabaseHelper:
public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
private static final String DATABASE_NAME = "qzeodemo.db";
private static final int DATABASE_VERSION = 1;
private Dao<ModifierDetails, Integer> itemsDao;
private Dao<ItemDetails, Integer> modifiersDao;
public DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION, R.raw.ormlite_config);
}
#Override
public void onCreate(SQLiteDatabase sqliteDatabase, ConnectionSource connectionSource) {
try {
// Create tables. This onCreate() method will be invoked only once of the application life time i.e. the first time when the application starts.
TableUtils.createTable(connectionSource,ItemDetails.class);
TableUtils.createTable(connectionSource,ModifierDetails.class);
} catch (SQLException e) {
Log.e(DatabaseHelper.class.getName(), "Unable to create datbases", e);
}
}
#Override
public void onUpgrade(SQLiteDatabase sqliteDatabase, ConnectionSource connectionSource, int oldVer, int newVer) {
try {
// In case of change in database of next version of application, please increase the value of DATABASE_VERSION variable, then this method will be invoked
//automatically. Developer needs to handle the upgrade logic here, i.e. create a new table or a new column to an existing table, take the backups of the
// existing database etc.
TableUtils.dropTable(connectionSource, ItemDetails.class, true);
TableUtils.dropTable(connectionSource, ModifierDetails.class, true);
onCreate(sqliteDatabase, connectionSource);
} catch (SQLException e) {
Log.e(DatabaseHelper.class.getName(), "Unable to upgrade database from version " + oldVer + " to new "
+ newVer, e);
}
}
// Create the getDao methods of all database tables to access those from android code.
// Insert, delete, read, update everything will be happened through DAOs
public Dao<ItemDetails,Integer> getItemDao() throws SQLException {
if (itemsDao == null) {
itemsDao = getDao(ItemDetails.class);
}
return itemsDao;
}
public Dao<ModifierDetails, Integer> getMofifierDao() throws SQLException {
if (modifiersDao == null) {
modifiersDao = getDao(ModifierDetails.class);
}
return modifiersDao;
}
}
The line where i am using modifiersDao = getDao(ModifierDetails.class); is giving error
Error:(76, 30) error: invalid inferred types for D; inferred type does not conform to declared bound(s)
inferred: Dao
bound(s): Dao
where D,T are type-variables:
D extends Dao declared in method getDao(Class)
T extends Object declared in method getDao(Class)
Please help :(
Your declaration is wrong above:
private Dao< ItemDetails, Integer > modifiersDao;
but getMofifierDao() returns Dao< ModifierDetails, Integer>

What is the best way of creating greenDAO DB connection only once for single run of application?

Currently I am creating the greenDAO DB connection in a class (which opens the connection in every static method) and using it wherever I need it. But I am not sure if it's the best way of doing it.
Can anyone suggest a better way of doing it?
My Code:
import com.knowlarity.sr.db.dao.DaoMaster;
import com.knowlarity.sr.db.dao.DaoMaster.DevOpenHelper;
import com.knowlarity.sr.db.dao.DaoSession;
import com.knowlarity.sr.db.dao.IEntity;
public class DbUtils {
private static Object lockCallRecord =new Object();
private DbUtils(){};
public static boolean saveEntity(Context context , IEntity entity){
boolean t=false;
DevOpenHelper helper=null;
SQLiteDatabase db=null;
DaoMaster daoMaster=null;
DaoSession daoSession =null;
try{
helper = new DaoMaster.DevOpenHelper(context, IConstant.DB_STRING, null);
db = helper.getReadableDatabase();
daoMaster = new DaoMaster(db);
daoSession = daoMaster.newSession();
//Some business logic here for fetching and inserting the data.
}catch (Exception e){
Log.e("saveEntity", e.getStackTrace().toString());
}finally{
if(daoSession!=null)daoSession.clear();
daoMaster=null;
if(db.isOpen())db.close();
helper.close();
}
return t;
}
Your approach causes the database to be loaded very often which is not necessary and may slow down your app significantly.
Open the database once and store it somewhere and request it from there if needed.
Personally I use a global DaoSession and local DaoSessions. The local DaoSessions get used where nothing should remain in the session cache (i.e. persisting a new object into the database, that is likely to be used only very infrequent or performing some queries which will load a lot of entities that are unlikely to be reused again).
Keep in mind that updating entities in a local DaoSession is a bad idea if you use the entity in your global session as well. If you do this the cached entity in your global session won't be updated and you will get wrong results unless you clear the cache of the global session!
Thus the safest way is to either just use one DaoSession or new DaoSessions all the time and to not use a global and local sessions!!!
A custom application class is a good place, but any other class will also be ok.
This is how I do it:
class DBHelper:
private SQLiteDatabase _db = null;
private DaoSession _session = null;
private DaoMaster getMaster() {
if (_db == null) {
_db = getDatabase(DB_NAME, false);
}
return new DaoMaster(_db);
}
public DaoSession getSession(boolean newSession) {
if (newSession) {
return getMaster().newSession();
}
if (_session == null) {
_session = getMaster().newSession();
}
return _session;
}
private synchronized SQLiteDatabase getDatabase(String name, boolean readOnly) {
String s = "getDB(" + name + ",readonly=" + (readOnly ? "true" : "false") + ")";
try {
readOnly = false;
Log.i(TAG, s);
SQLiteOpenHelper helper = new MyOpenHelper(context, name, null);
if (readOnly) {
return helper.getReadableDatabase();
} else {
return helper.getWritableDatabase();
}
} catch (Exception ex) {
Log.e(TAG, s, ex);
return null;
} catch (Error err) {
Log.e(TAG, s, err);
return null;
}
}
private class MyOpenHelper extends DaoMaster.OpenHelper {
public MyOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory) {
super(context, name, factory);
}
#Override
public void onCreate(SQLiteDatabase db) {
Log.i(TAG, "Create DB-Schema (version "+Integer.toString(DaoMaster.SCHEMA_VERSION)+")");
super.onCreate(db);
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
Log.i(TAG, "Update DB-Schema to version: "+Integer.toString(oldVersion)+"->"+Integer.toString(newVersion));
switch (oldVersion) {
case 1:
db.execSQL(SQL_UPGRADE_1To2);
case 2:
db.execSQL(SQL_UPGRADE_2To3);
break;
default:
break;
}
}
}
In application class:
private static MyApplication _INSTANCE = null;
public static MyApplication getInstance() {
return _INSTANCE;
}
#Override
public void onCreate() {
_INSTANCE = this;
// ...
}
private DBHelper _dbHelper = new DBHelper();
public static DaoSession getNewSession() {
return getInstance()._dbHelper.getSession(true);
}
public static DaoSession getSession() {
return getInstance()._dbHelper.getSession(false);
}
Of course you can also store the DaoMaster instead of the DB itself. This will reduce some small overhead.
I'm using a Singleton-like Application class and static methods to avoid casting the application (((MyApplication)getApplication())) every time I use some of the common methods (like accessing the DB).
I would recommend to create your database in your Application class. Then you can create a method to return the DaoSession to get access to the database in other Activities.

How to make the data to be inside the database without the need to wait for the data to be inserted one by one?

How is it that some dictionaries such as merriam dictionary (Offline dictionary) when the application was installed , the words are there instantly, and time is not required to insert a list of words and definition into the database? I am a beginner and is currently developing an android application that consist of about 30K words and it will take around 15+ minutes for it to insert all the data into the database before the user can search for that particular data. And I am looking for a method that can fix this. Could someone please tell me a way to do it ?
Thank you
My guess is that these apps are using an already SQLite database with all the data they need already populated.
You can import populated databases to your app with something like this :
public class DataBaseAdapter {
String DB_NAME = "DBNAME.db";
String DIR = "/data/data/packageName/databases/";
String DB_PATH = DIR + DB_NAME;
private DataBaseHelper mDbHelper;
private SQLiteDatabase db;
private Context context;
public DataBaseAdapter(Context context) {
this.context = context;
mDbHelper = new DataBaseHelper(this.context);
}
class DataBaseHelper extends SQLiteOpenHelper {
private boolean createDatabase = false;
#SuppressWarnings("unused")
private boolean upgradeDatabase = false;
Context context;
public DataBaseHelper(Context context) {
super(context, DB_NAME, null, 1);
this.context = context;
}
public void initializeDataBase() {
getWritableDatabase();
if (createDatabase) {
try {
copyDataBase();
} catch (IOException e) {
throw new Error("Error copying database");
}
}
}
private void copyDataBase() throws IOException {
InputStream input = context.getAssets().open(DB_NAME);
OutputStream output = new FileOutputStream(DB_PATH);
byte[] buffer = new byte[1024];
int length;
try {
while ((length = input.read(buffer)) > 0) {
output.write(buffer, 0, length);
}
}
finally {
try {
if (output != null) {
try {
output.flush();
} finally {
output.close();
}
}
} finally {
if (input != null) {
input.close();
}
}
}
getWritableDatabase().close();
}
public void onCreate(SQLiteDatabase db) {
createDatabase = true;
}
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
upgradeDatabase = true;
}
public void onOpen(SQLiteDatabase db) {
super.onOpen(db);
}
}
public DataBaseAdapter open() {
mDbHelper.initializeDataBase();
if (db == null)
db = mDbHelper.getWritableDatabase();
return this;
}
public void close() {
db.close();
}
}
you can then add methods to get data from database and this class can be used in your activity by calling open then the method to get data then close.
Your application should include a pre-populated database for offline access with it's install. That will avoid each user having to run the INSERT step on their device.
Is there a particular reason you need to run the INSERTS post-install?

Ormlite database helper - onCreate() not called

I am using ormlite.android.4.31.jar
I have typical DatabaseHelper
public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
private static final String DATABASE_NAME = "realestate.db";
private static final int DATABASE_VERSION = 1;
private Dao<TabKraj, Integer> krajDao;
public DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
#Override
public void onCreate(SQLiteDatabase sqliteDatabase, ConnectionSource connectionSource) {
try {
TableUtils.createTable(connectionSource, TabKraj.class);
initData();
} catch (Exception e) {
Log.e(DatabaseHelper.class.getName(), "Unable to create datbases", e);
}
}
#Override
public void onUpgrade(SQLiteDatabase sqliteDatabase, ConnectionSource connectionSource, int oldVer, int newVer) {
try {
TableUtils.dropTable(connectionSource, TabKraj.class, true);
onCreate(sqliteDatabase, connectionSource);
} catch (SQLException e) {
Log.e(DatabaseHelper.class.getName(), "Unable to upgrade database from version " + oldVer + " to new " + newVer, e);
}
}
public Dao<TabKraj, Integer> getKrajDao() throws SQLException{
if (krajDao == null) {
krajDao = getDao(TabKraj.class);
}
return krajDao;
}
private void initData(){
Log.d(Constants.DEBUG_TAG, "data initiating");
TabKraj k1 = new TabKraj();
TabKraj k2 = new TabKraj();
k1.setNazov("Kosicky kraj");
k1.setId(1);
try {
getKrajDao().create(k1);
} catch (SQLException e) {
Log.e(Constants.DEBUG_TAG, "Data initialing ERROR");
}
}
}
app is uninstalled, data cleared ...
I am running app in debug mode from eclipse, constructor of DatabaseHleper is called but onCreate() is not called.
Where could the problem be?
As #k-mera said:
Database file will be created only if you did some operations in Database like "insert".
Although you say the data is cleared, I suspect that Android thinks it has not. To completely remove the data, I would remove the application and re-install it.
Since your onUpgrade calls onCreate you could also increase the DATABASE_VERSION value which will cause the data to be dropped and re-created.

Categories

Resources