views:

59

answers:

3

One of my applications downloads a database from a server. When I install the application onto my phone, it downloads the file correctly and loads the information, no exceptions thrown or anything.

However, when I upload the apk into the Android Market Place and download it onto the phone, the application downloads the database and then crashes, saying that the sqlite handler was not able to open up the database.

Here's the progression of code:

In the SQLiteOpenHelper:

this.FULL_DB_PATH = new String(this.getWritableDatabase().getPath());
this.getWritableDatabase();

// Code for retrieving the database off of the server:

private void copyDataBase(){
        InputStream myInput=null;
        OutputStream myOutput=null;
        try{
            // opening connections
            URL url = new URL("server_url_here");
            URLConnection ucon=url.openConnection();
            myInput = ucon.getInputStream();     
            myOutput = new FileOutputStream(this.FULL_DB_PATH);

            // write to the db here
            byte[] buffer = new byte[1024*1024];
            int length;
            while ((length = myInput.read(buffer))>0){
                myOutput.write(buffer, 0, length);
            }

            myOutput.flush();
            myOutput.close();
            myInput.close();
        }
         catch(Exception e)
         {

                try{
                    myOutput.flush();
                    myOutput.close();
                    myInput.close();
                }
                catch(Exception es){}
         }
    }

I don't know why my colleague is saving the db with a mp3 extension but...it works when we're installing the apk ad-hoc.

For:

myOutput = new FileOutputStream(this.FULL_DB_PATH);

I've also tried:

myOutput = this.getApplicationContext().openFileOutput(this.FULL_DB_PATH, Context.MODE_WORLD_READABLE);

But that doesn't work either.

Any help is greatly appreciated!! I've been tearing my hair out for a couple of hours over this and I just want it to end haha.

+1  A: 

The Emulator gives you special access that real phones don't. In other words, I suspect you are directly copying the file into the databases directory on the phone? If so, you can't do that on a non-rooted phone. Hopefully someone will chime in and prove me wrong because this is a problem for me too. I'd like to easily download a db file and install it. What I end up having to do as a work-around is create a new database and load the schema and data through queries.

EDIT: I would like to share a trick with you. It's simple really. Instead of using just db.insert/db.update/ by themselves, scope them into transactions. In fact, I would scope the whole DB Build as a transaction, or at least just individual tables. I've experienced a 10-50x increase in speed of transactions when they're scoped and then committed all at once.

Brad Hein
Have you tried packaging the database with the app bundle and uploading that?When I tried this, my app was about 40 something MB but it wouldn't upload to the store...
K-RAN
Woah that's a big DB. I would consider keeping your DB on the server side. Also have a DB on the local phone, but allow the phone to only download "stuff that it needs" "as it needs it". So the local DB is a cache of only the parts of the 40MB DB that are relevant to the given subscriber. 40MB is quite big, although I'm sure it's all importand stuff
Brad Hein
+1  A: 

What you are doing is copying the file into the /data folder in the android file system. On a normal phone with normal permissions this is not allowed for security reasons. You can do this on the emulator and rooted phones because you have been granted permission to write to /data (normally only read).

To get around this you will need to manually add the information to the database using db.insert(String, String, ContentValues) and db.update(String, ContentValues, String, String[])

It would be nice to be able to do what you are trying but for security reasons it's a very good thing you can't.

matto1990
But what about packaging the app with a pre-built database? I have a huge amount of data and manually inserting all of the data would make the app unusable from a user perspective.
K-RAN
You have 2 options really. If you can provide it in XML format you can add it to the res/xml folder of your project and then access it from there. I can provide code in another answer if this is the option you are after. The other open is to download a file from the server at first run and then go through the file adding each row. This could be in XML or JSON, or soemthing else like that. Generally having it as XML is the recommended way of doing it, but wither will work.
matto1990
adding the pre-built db directly into the res folder of eclipse wont do it? I'm confused...especially because in the original build that I had, I had the db included in the res folder for the project but the apk itself never finished uploading.
K-RAN
A: 

The other two answers are incorrect, I do believe. I have a backup system in my app where backups are copied to the sd-card, and then copied back to the /data/-folder when the backup is restored. While I have no idea why your code wont work, here is my code to copy the database from the sd-card:

final InputStream in = new FileInputStream(from);
final OutputStream out = new FileOutputStream(to);
final byte[] buf = new byte[1024];
int len;
while ((len = in.read(buf)) > 0){
    out.write(buf, 0, len);
}
in.close();
out.close();

Just to closer investigare the error, try to download to the sd-card instead and then use my code to copy it to the data-folder. The "to" object in my code I get like this:

public static final String DATABASE_PATH = "/data/data/"+SomeClass.class.getPackage().getName()+"/databases/"+ DATABASE_NAME;
final File to = new File(Constant.DATABASE_PATH);
sandis