1

EDIT: The app is crashing on mobile phones with Android version 2.3.5

I have uploaded my first app on Google Play yesterday, today I got error report with the follwoing:

android.database.sqlite.SQLiteException: unable to open database file
at android.database.sqlite.SQLiteDatabase.dbopen(Native Method)
at android.database.sqlite.SQLiteDatabase.<init>(SQLiteDatabase.java:1956)
at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:918)
at com.hazcheck.dgl.data.ExternalDBOpenHelper.openDataBase(ExternalDBOpenHelper.java:96)
at com.hazcheck.dgl.SearchActivity.afterTextChanged(SearchActivity.java:284)
at android.widget.TextView.sendAfterTextChanged(TextView.java:6566)
at android.widget.TextView$ChangeWatcher.afterTextChanged(TextView.java:6989)
at android.text.SpannableStringBuilder.sendTextHasChanged(SpannableStringBuilder.java:897)
at android.text.SpannableStringBuilder.change(SpannableStringBuilder.java:353)
at android.text.SpannableStringBuilder.change(SpannableStringBuilder.java:269)
at android.text.SpannableStringBuilder.replace(SpannableStringBuilder.java:432)
at android.text.SpannableStringBuilder.replace(SpannableStringBuilder.java:409)
at android.text.SpannableStringBuilder.replace(SpannableStringBuilder.java:28)
at android.view.inputmethod.BaseInputConnection.replaceText(BaseInputConnection.java:679)
at android.view.inputmethod.BaseInputConnection.commitText(BaseInputConnection.java:185)
at com.android.internal.widget.EditableInputConnection.commitText(EditableInputConnection.java:120)
at com.android.internal.view.IInputConnectionWrapper.executeMessage(IInputConnectionWrapper.java:332)
at com.android.internal.view.IInputConnectionWrapper$MyHandler.handleMessage(IInputConnectionWrapper.java:86)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:143)
at android.app.ActivityThread.main(ActivityThread.java:4268)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:507)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
at dalvik.system.NativeStart.main(Native Method)

EDIT: Here is my SQLiteOpenHelper class, I might be doing something wrong, please check it out:

package com.hazcheck.dgl.data;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
//import java.util.zip.ZipInputStream;

import com.hazcheck.dgl.R;

import android.content.Context;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;
//import android.content.res.Resources;

public class ExternalDBOpenHelper  extends SQLiteOpenHelper{

    //public static int DB_PATH_ID; 
    public static String DB_NAME;
    public static String DB_PATH;
    public static int DB_VERSION;
    public SQLiteDatabase database;
    public final Context context;

    //private Resources resources;

    public SQLiteDatabase getDb() {
        return database;
    }
        public ExternalDBOpenHelper(Context context) {
        super(context, DB_NAME = context.getString(R.string.app_data_name), null, DB_VERSION = Integer.parseInt((context.getString(R.string.app_database_version))));
        this.context = context;
        String packageName = context.getPackageName();
        //resources = context.getResources();
        //DB_PATH_ID = R.raw.imdg35;
        DB_PATH = String.format("//data//data//%s//databases//", packageName);

        openDataBase(); //createDataBase();
    }


    public void createDataBase() {
        boolean dbExist = checkDataBase();
        if (!dbExist) {
            this.getReadableDatabase();
            try {
                copyDataBase();
            } catch (IOException e) {
                Log.e(this.getClass().toString(), "Copying error");
                throw new Error("Error copying database!");
            }
        } else {
            Log.i(this.getClass().toString(), "Database already exists");
        }
    }

    private boolean checkDataBase() {
        String path = DB_PATH + DB_NAME;
        File dbFile = new File(path);
        return dbFile.exists();
    }

    private void copyDataBase() throws IOException {
        InputStream externalDbStream = context.getAssets().open(DB_NAME);

        String outFileName = DB_PATH + DB_NAME;

        OutputStream localDbStream = new FileOutputStream(outFileName);

    byte[] buffer = new byte[1024];
    int bytesRead;
    while ((bytesRead = externalDbStream.read(buffer)) > 0) {
        localDbStream.write(buffer, 0, bytesRead);
    }

    localDbStream.close();
    externalDbStream.close();
/*  String outFileName = DB_PATH + DB_NAME;
    InputStream is = resources.openRawResource(DB_PATH_ID);
    OutputStream myOutput = new FileOutputStream(outFileName);
    ZipInputStream zis = new ZipInputStream(new BufferedInputStream(is));
    try {
        while (zis.getNextEntry() != null) {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            byte[] buffer = new byte[1024];
            int count;
            while ((count = zis.read(buffer)) != -1) {
                baos.write(buffer, 0, count);
                //Log.d("", buffer.toString());
            }
            baos.writeTo(myOutput);
        }
    }
    finally{
        zis.close();
        myOutput.flush();
        myOutput.close();
        is.close();
    }*/
}

public SQLiteDatabase openDataBase() throws SQLException {
    String path = DB_PATH + DB_NAME;
    if (database == null) {
        createDataBase();
        database = SQLiteDatabase.openDatabase(path, null,  SQLiteDatabase.OPEN_READWRITE);
    }
    return database;
}
@Override
public synchronized void close() {
    if (database != null) {
        database.close();
    }
    super.close();
}
@Override
public void onCreate(SQLiteDatabase db) {}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {}
}
SamSPICA
  • 1,366
  • 15
  • 31
m.othman
  • 638
  • 7
  • 28
  • RU copying to SDcard? if SDcard is not there mean what you are doing? Ru creating Folder(mkdir) inside SDCard? – Padma Kumar Apr 11 '12 at 08:58
  • are you sure the database is done copying before the search occurs? – njzk2 Apr 11 '12 at 09:56
  • I tested the app on different devices and different Android version before uploading it on the Market, it always worked fine. If any one has Android mobile can also try it, in Google Play look for the word "DGL" and install the app with red H diamond icon – m.othman Apr 11 '12 at 11:18
  • Did you try debugging the app step-by-step (with the device on which it is crashing)? That might probably show the location where the app is getting stuck, n ultimately find / rectify the error. – SamSPICA Apr 12 '12 at 13:30
  • @SamSPICA: you made a good point, but I am very new to Android programming and don't know how to debug it with actual device, any articles or blog? I also wanted to test it with a 2.3.5 Android emulator but there is no way to install that version! – m.othman Apr 12 '12 at 21:17
  • Solution for me: Cause of this error was due to devices running out of (internal) memory. The cache was then cleaned by Android and my database with it. – Someone Somewhere May 23 '13 at 22:14

4 Answers4

0

1) Which is the database you are referring to at this line: com.hazcheck.dgl.SearchActivity.afterTextChanged(SearchActivity.java:284)? Does the respective database exist? Have you instantiated / created the database in the OnCreate() method? If not, there's your error. You probably tested the app on your device, where you created it only the first time; where the app then re-uses the database even if you replace the application package.

2) About the "1 error report, while 0 installs", this has happened to my application as well. Probably the process of updating the number of installs is periodic, while updating the error log is instant.

SamSPICA
  • 1,366
  • 15
  • 31
  • afterTextChanged calls a method Search which actually instantiate the database, if not already instantiated, and then open the database, ExternalDBOpenHelper dbOpenHelper = new ExternalDBOpenHelper(getBaseContext()); I don't actually instantiate it in onCreate(). – m.othman Apr 11 '12 at 11:12
  • IMHO, it would be better to create an instance of the database in the onCreate() stub, so as to avoid any further issues. creating a private field db variable might prove fruitful. – SamSPICA Apr 11 '12 at 11:26
  • I applied what you told me and sent it for testing, I hope it will work fine. Another thing, the current one on the market didn't work on one HTC WildFire but worked on another similar device HTC WildFire, weird. I have edited my question and added another function that I use to read the database – m.othman Apr 11 '12 at 14:32
  • Testing finished, it still fails on some mobiles and work on others. I don't understand this issue... We also tried it on two HTC WildFire (exactly the same) and it worked on one but failed on another. Any more ideas? – m.othman Apr 11 '12 at 17:12
  • Will it be possible to post the Log where the app fails, so that we may look into what is actually going wrong? Apps working on emulator, but not on device is common, but inconsistency on two devices of the same make is confusing. – SamSPICA Apr 11 '12 at 17:37
  • The error log as reported on Android is on top of my question above. I just got information that the phones are not exactly the same! one of them is HTC WildFire (working fine) and the other is HTC WildFire S (not working)... The error is appearing on **Android version 2.3.5** – m.othman Apr 12 '12 at 10:26
  • @m.othman: Are you using the same database for all the devices? If that is the case, this might be an answer to your issue: [SQLiteException: unable to open...](http://stackoverflow.com/a/6727146/713354) Database created on one version of android **may not** be usable on another version, and thus the problems. Also, another link to look into: [SQLiteException: Context Issue](http://stackoverflow.com/a/6556145/713354). – SamSPICA Apr 12 '12 at 11:02
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/10003/discussion-between-samspica-and-m-othman) – SamSPICA Apr 12 '12 at 13:31
  • I am sorry, I missed the chat! I just saw your comment. Lets chant again tomorrow afternoon. Thanks all for your support – m.othman Apr 12 '12 at 21:19
0
    > String outFileName = DB_PATH + DB_NAME;

this may be a problem depending if the app is installed on sd-card or in phone memory.

The class DatabaseContext and its decendants (like Activity) have a method

    File getDatabasePath(String name)

that should give you the correct directory.

k3b
  • 14,517
  • 7
  • 53
  • 85
  • What my copyDataBase function does is, create a new file using DB_PATH + DB_NAME if the file is not yet there, which is the case at first time run. Then unzip the compressed database residing in raw folder and move its content to the newly created file. The database path is DB_PATH = String.format("//data//data//%s//databases//", packageName); – m.othman Apr 11 '12 at 10:01
  • thanks for help. I have tried your solution but it didn't work. Any other suggestions? – m.othman Apr 18 '12 at 15:44
0

I found that the problem is in the database itself, it was created with an old Sqlite version. Now, I used Sqlite 3.7.11 and recreated the database and now it works just fine.

m.othman
  • 638
  • 7
  • 28
0

In my Case when I open the database with databaseInstance with this method

private static boolean openDB(String dbPathWithName) {
        boolean status = true;
        try {
            if (databaseInstance == null || !databaseInstance.isOpen()){
                databaseInstance = SQLiteDatabase.openDatabase(dbPathWithName, null, SQLiteDatabase.OPEN_READWRITE + SQLiteDatabase.CREATE_IF_NECESSARY);

            }
        } catch (Exception ex){
            status = false;
            NGAndroidUtil.logErr("DataHelper", ex.getMessage(), ex);
        }
        return status;
    }

In this it throw the exception "unable to Open the database " ....In this I am not give the path of database in correct format thats why it throw the exception "unable to open the database...Make sure the path of database in correct format which you want to open..

Geek_shiva
  • 91
  • 1
  • 2