0

I use the following code to add rows to my database :

    public void insert(String kern, String woord) {
      SQLiteDatabase db = getWritableDatabase();

      ContentValues values = new ContentValues();
      values.put(KERN, kern);
      values.put(WOORD, woord);

      db.insertOrThrow(TABLE_NAME, null, values);
      return;

Currently, I'm invoking this insert() 3.455 times, to add all words to the database, using : insert("Fruits", "Banana"); It takes forever.

How can I change this code to work faster? I'm thinking in the line of foreach, but don't know how to implement.. Thanks!

/Edit; The solution provided by @hovanessyan works and will do the job. AND.. note that if you have a lot of lines that have to be put in, you might be confronted with the method exceeds max byte limit error. In that case, review the other solution, that suggests packing the database in the actual .APK file.

Kees Koenen
  • 772
  • 2
  • 11
  • 27

3 Answers3

4

You can wrap-up those inserts into transaction.

db.beginTransaction();
 try {
  // do all the inserts here

  //method call here, that does 1 insert; For example
  addOneEntry(kern,woord);
  ... 
  db.setTransactionSuccessful();
 } catch (SQLException e) {
         //catch exceptions
 } finally {
   db.endTransaction();
 }


 private void addOneEntry(String kern, String woord) {
   //prepare ContentValues
   //do Insert
 }
hovanessyan
  • 30,580
  • 6
  • 55
  • 83
  • ... and the theory behind it would be that if you don't then SQLite will commit on every insert (auto-commit behavior), which slows you down. –  Nov 06 '11 at 14:58
  • Thanks! So.. that means, in your example, I'd do inserts by `db.insertOrThrow(TABLE_NAME, null, values);` ? Then how do I get, for instance, the "Fruits" , "Bananas" in there without using ContentValues? i.e. What should be the syntax instead of "values"? – Kees Koenen Nov 06 '11 at 15:10
  • You actually still use ContentValues. – hovanessyan Nov 06 '11 at 15:13
  • Thanks Guys and Gals! I changed the code to ` try { ContentValues values = new ContentValues(); values.put(KERN, "music");values.put(WOORD, "piano"); db.insertOrThrow(TABLE_NAME, null, values); //And so on... db.setTransactionSuccessful(); } finally { db.endTransaction(); }` and it works! now.. for some Notepad++ing to get those 3,5K variables in there :) – Kees Koenen Nov 06 '11 at 15:24
  • Bummer.. I get the exceeding the 65535 bytes limit error.. :( – Kees Koenen Nov 06 '11 at 18:18
  • so what was your question? Getting speed or deal with some exceeding bytes limit error? Maybe you should revise your question... – hovanessyan Nov 06 '11 at 19:30
  • @hovanessyan getting speed was the question, but when trying the solution, I was confronted with the ebl error.. I'll edit the question, thanks! – Kees Koenen Nov 07 '11 at 12:04
0

You can use bulkInsert:

   ContentValues[] cvArr = new ContentValues[rows.size()];
   int i = 0;
   for (MyObject row : rows) {
    ContentValues values = new ContentValues();
    values.put(KERN, myObject.getKern());
    values.put(WOORD, myObject.getWoord);       
    cvArr[i++] = values;
    }// end for
    resolver.bulkInsert(Tasks.CONTENT_URI, cvArr);
Damian
  • 8,062
  • 4
  • 42
  • 43
  • I see. What is MyObject in this example? And how is it formatted? First answer works for me, but confronts me with exceeding the 65535 bytes limit... :(. – Kees Koenen Nov 06 '11 at 15:43
  • 1
    MyObject is just a class that holds the values you want to store e.g. class MyObject { private String kern; private String woord; public String getKern() { return kern; } public String getWoord() { return woord; } } – Damian Nov 06 '11 at 15:45
  • Ah. Ok. But this doesn't help the exceeding the 65535 bytes limit-problem. More I come to think about it, I might want to use a Values file to store the entire dictionary and read it with code?.. more to research :) – Kees Koenen Nov 06 '11 at 15:56
  • I'll take a look at shipping the Database with the app (http://stackoverflow.com/questions/2887119/populate-android-database-from-csv-file). Issue was, that I want to enable the user to rebuild the original database any time.. I could just copy the shipped one over the built one, I guess.. – Kees Koenen Nov 06 '11 at 16:02
  • Better yet; I'll pre-ship a database containing two tables; one with the standard dictionairy, one containing user-definable words (that can be cleared in the App).. I'll post the solution as soon as I figure it out.. – Kees Koenen Nov 06 '11 at 16:49
0

Using the tips of both hovanessyan and Damian (remind me to rep+1 you as soon as I reach 15 ;), I came up with the following solution:

  1. For relatively small databases (<1,5Mb)

I created the database using SQLite Database Browser, and put it in my Assets folder.

Then, the following code copies the database to the device, if it's not already there:

    boolean initialiseDatabase = (new File(DB_DESTINATION)).exists();

public void copyDB() throws IOException{ final String DB_DESTINATION = "/data/data/happyworx.nl.Flitswoorden/databases/WoordData.db";

    // Check if the database exists before copying


    Log.d("Database exist", "" + initialiseDatabase);
    Log.d("Base Context", "" + getBaseContext());

    if (initialiseDatabase == false) {

        // Open the .db file in your assets directory
        InputStream is = getBaseContext().getAssets().open("WoordData.db");


        // Copy the database into the destination
        OutputStream os = new FileOutputStream(DB_DESTINATION);
        byte[] buffer = new byte[1024];
        int length;
        while ((length = is.read(buffer)) > 0){
            os.write(buffer, 0, length);
        }
        os.flush();

        os.close();
        is.close();
    }}

In my app, a portion of the database is User-customizable.

I call the code above in onStart() with :

        try {
        copyDB();
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

So, when the user presses "reset database to standard" (in preferences screen), I just set the Boolean initialiseDatabase to "false" and wait for the user to go back to the main activity. (thus calling onstart and copying the original database).

I tried to call the Activity.copyDB() from the preferences.java. It's neater, because it doesn't require the user to go back to the main activity to rebuild the database. However, I get an error about not being able to call static references to non-static methods. I don't understand that, but will look into it.

Kees Koenen
  • 772
  • 2
  • 11
  • 27