Code improvement and new features added
Post date: Jun 9, 2012 3:14:00 PM
I have been making some good progress on my first app and getting it slowly working the way I want it to. I have added Speech Recognition that will allow the user to say what they think the Spanish word is in English and I compare that word with the one from my database then notify the user if they are correct or not. I have also added Text-to-Speech (TTS) so the user can hear how the word is pronounced correctly when learning how to speak the language. The next items that I will be working on will be the settings database, the menu and the settings page. I don’t think it will be very hard to get those working but it will take a little time to get everything I need created.
When trying to copy my premade SQLite database into my app I found this website on ReignDesignthat helped a lot. It showed me how to modify the database to work with Android and some code to get it working. It took me some time to play with the code in order to get it to work for me but I was able to get it working. Bellow is the code from the website that I used.
/** * Creates an empty database on the system and rewrites it with your own database. * */ public void createDataBase() throws IOException{ boolean dbExist = checkDataBase(); if(dbExist){ //do nothing - database already exist }else{ //By calling this method and empty database will be created into the default system path //of your application so we are gonna be able to overwrite that database with our database. this.getReadableDatabase(); try { copyDataBase(); } catch (IOException e) { throw new Error("Error copying database"); } } } /** * Check if the database already exist to avoid re-copying the file each time you open the application. * @return true if it exists, false if it doesn't */ private boolean checkDataBase(){ SQLiteDatabase checkDB = null; try{ String myPath = DB_PATH + DB_NAME; checkDB = SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.OPEN_READONLY); }catch(SQLiteException e){ //database does't exist yet. } if(checkDB != null){ checkDB.close(); } return checkDB != null ? true : false; } /** * Copies your database from your local assets-folder to the just created empty database in the * system folder, from where it can be accessed and handled. * This is done by transfering bytestream. * */ private void copyDataBase() throws IOException{ //Open your local db as the input stream InputStream myInput = myContext.getAssets().open(DB_NAME); // Path to the just created empty db String outFileName = DB_PATH + DB_NAME; //Open the empty db as the output stream OutputStream myOutput = new FileOutputStream(outFileName); //transfer bytes from the inputfile to the outputfile byte[] buffer = new byte[1024]; int length; while ((length = myInput.read(buffer))>0){ myOutput.write(buffer, 0, length); } //Close the streams myOutput.flush(); myOutput.close(); myInput.close(); } public void openDataBase() throws SQLException{ //Open the database String myPath = DB_PATH + DB_NAME; myDataBase = SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.OPEN_READONLY); } @Override public synchronized void close() { if(myDataBase != null) myDataBase.close(); super.close(); } @Override public void onCreate(SQLiteDatabase db) {}
There is a few other parts of the code that can be found on his website but this is the part of the code that I had some fun with. He said to call the createDataBase() function to copy the data over.
I have an option to update a column in my the database so the user can mark the word and come back to it later if they want to practice it more. When I was able to update the mark column I found something odd that took me a little to realize what was going on. Every time I would go into my app and mark some words I would be able to pull those words showing that the database was changed but when I would exit the app and open it again, all the changes to the database would go away. It turns out that every time I called the createDataBase function it would copy the database and over write it instead of seeing that it was already there and skipping it. This was a real problem for me and the function of my app.
After a little thinking and looking over the code I found a solution to my problem. In other Android database apps (like the one in the Hack-a-Day tutorial) uses the SQL Database Helper onCreate() method to create the tables of the database. I looked it up and the onCreate() method is called one time when the database is first created and that is just what I needed. I was limited to what I could have onCreate() do for me, it only liked to use strings. So I thought of a way of letting it use strings and still getting what I need from it. I created a new string variable called newDatabase and set it to equal “0″ then I told onCreate() to change newDatabase to equal “1″. When you tell SQL helper to open a database and it is not there, it will create it and that triggers the onCreate() method. So I open and close the database right when my app first loads, that runs onCreate() and sets newDatabase to “1″. Also when my app first runs I have an if statement that says if newDatabase = 1 then run copyDataBase(). With this I was able to remove the need for the createDataBase and checkDataBase methods and allow my app to run a little smother. The code I used is below.
In my database adapter class.
public class WordsDBAdapter { //Call this to open the database public WordsDBAdapter open() throws SQLException { //Opens the database but if the database named is not found it will create it. Db = dbHelp.getWritableDatabase(); return this; } //call this to close the database public void close() { Db.close(); } public void copyDataBase() throws IOException { //This is the path to the empty database. String outFileName = DB_PATH + DB_NAME; //Opens the empty database as the output stream. OutputStream myOutput = new FileOutputStream(outFileName); //Open the premade assets database as the input stream. InputStream myInput = context.getAssets().open(DB_NAME); //This transfers the bytes from the inputfile to the outputfile. byte[] buffer = new byte[1024]; int length; while ((length = myInput.read(buffer))>0) { myOutput.write(buffer, 0, length); } //Close the streams when finished. myOutput.flush(); myOutput.close(); myInput.close(); } public static class dBHelper extends SQLiteOpenHelper { public dBHelper (Context context, String dbName, Object object, int databaseVersion) { super(context, DB_NAME, null, DATABASE_VERSION); } //This is called when the database is created. @Override public void onCreate(SQLiteDatabase db) { SpanishMain.newDatabase = "1"; } //This is called when the database is out of date. @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { Log.w(TAG, "Upgrading database from version " + oldVersion + " to " + newVersion + ", which will remove all marked words."); db.execSQL("DROP TABLE IF EXISTS " + DB_TABLE); } } } In my main class. public class SpanishMain extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //Sets and creates the layout. setContentView(R.layout.main); //Opens or creates the database depending on if it is there dBHelp.open(); dBHelp.close(); //If the database was not there, an empty database was created and on create set newDatabase to 1 if (newDatabase.contains("1")) { try { dBHelp.copyDataBase(); } catch (IOException e) { e.printStackTrace(); } dBHelp.close(); } }