Android Sqlite singleton db filestream update failed

android, sqlite

Solution

I faced the same problem `database disk image is malformed` while I was trying to access database when it was updating itself. So, I followed the below way.

`DataBaseHelper`

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import android.content.Context;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteException;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;

public class DataBaseHelper extends SQLiteOpenHelper {

        private static final String TAG = DataBaseHelper.class.getSimpleName();
        private static String DB_PATH = "/data/data/YOUR_PACKAGE/databases/";
        private static String DB_NAME = "XXX";
        private SQLiteDatabase mDataBase;
        private final Context mContext;

        public DataBaseHelper(Context context) {
            super(context, DB_NAME, null, 1);
            DB_PATH = "/data/data/" + context.getPackageName() + "/databases/";
            this.mContext = context;
        }

        public void createDataBase() throws IOException {
            boolean mDataBaseExist = checkDataBase();
            if (!mDataBaseExist) {
                this.getReadableDatabase();
                try {
                    copyDataBase();
                } catch (IOException mIOException) {
                    throw new Error("ErrorCopyingDataBase");
                }
            }
        }

    private boolean checkDataBase() {
        SQLiteDatabase mCheckDataBase = null;
        try {
            String mPath = DB_PATH + DB_NAME;
            File pathFile = new File(mPath);
            if(pathFile.exists()) {
                mCheckDataBase = SQLiteDatabase.openDatabase(mPath, null, SQLiteDatabase.NO_LOCALIZED_COLLATORS);
            }
        } catch (SQLiteException mSQLiteException) {
            Log.e(TAG, "DatabaseNotFound " + mSQLiteException.toString());
        }

        if (mCheckDataBase != null) {
            mCheckDataBase.close();
        }
        return mCheckDataBase != null;
    }

    private void copyDataBase() throws IOException {
        final InputStream mInput = mContext.getAssets().open(DB_NAME);
        final String outFileName = DB_PATH + DB_NAME;
        OutputStream mOutput = new FileOutputStream(outFileName);
        byte[] mBuffer = new byte[1024];
        int mLength;
        while ((mLength = mInput.read(mBuffer)) > 0) {
            mOutput.write(mBuffer, 0, mLength);
        }
        mOutput.flush();
        mOutput.close();
        mInput.close();
    }

    public boolean openDataBase() throws SQLException {
        final String mPath = DB_PATH + DB_NAME;
        mDataBase = SQLiteDatabase.openDatabase(mPath, null,
        SQLiteDatabase.NO_LOCALIZED_COLLATORS);
        return mDataBase != null;
    }

    @Override
    public synchronized void close() {
        if (mDataBase != null)
            mDataBase.close();
        super.close();
    }

    @Override
    public void onCreate(SQLiteDatabase db) {}

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {}
}

`DBAdapter`

public class DBAdapter {

    private static final String TAG = DBAdapter.class.getSimpleName();
    private final Context mContext;
    private SQLiteDatabase mDb;
    private final DataBaseHelper mDbHelper;

    public DBAdapter(Context context) {
        this.mContext = context;
        mDbHelper = new DataBaseHelper(mContext);
    }

    public DBAdapter createDatabase() throws SQLException {
        try {
            mDbHelper.createDataBase();
        } catch (IOException mIOException) {
            throw new Error("UnableToCreateDatabase");
        }
        return this;
    }

    public DBAdapter open() throws SQLException {
        try {
            mDbHelper.openDataBase();
            mDbHelper.close();
            mDb = mDbHelper.getReadableDatabase();
        } catch (SQLException mSQLException) {
            Log.e(TAG, mSQLException.toString());
            throw mSQLException;
        }
        return this;
    }

    public void close() {
        mDbHelper.close();
    }
}

`Abhan` Extended Application Class

public class Abhan extends Application {

    public static final String TAG = Abhan.class.getSimpleName();
    public static final boolean DEBUG = true;
    private int androidVersion = 4;
    private DBAdapter dbAdapter = null;

    @Override
    public void onCreate() {
        super.onCreate();
        setAndroidVersion(android.os.Build.VERSION.SDK_INT);

        if(dbAdapter == null) {
            dbAdapter = new DBAdapter(getBaseContext());
            dbAdapter.createDatabase();
        }
    }

    public int getAndroidVersion() {
        return androidVersion;
    }

    public void setAndroidVersion(int androidVersion) {
        this.androidVersion = androidVersion;
    }

    public DBAdapter getDBInstatnce() {
        dbAdapter.open();
        return dbAdapter;
    }

    public void closeDataBase() {
        dbAdapter.close();
        if(DEBUG) {
            android.util.Log.d(TAG, "DataBase closed.");
        }
    }
}

In your `AndroidManifest`, Declare `Abhan`

<application
    android:name=".Abhan"
    android:allowBackup="false"
    android:icon="@drawable/ic_launcher"
    android:label="@string/app_name"
    android:theme="@style/AppTheme" >

In Your `Activity`, Access Your database using `Application` Class

private Abhan abhan;

In `onCreate`

    abhan = (Abhan) this.getApplication();

Now access your database transaction method like this.

   int currentDay = abhan.getDBInstatnce().getCurrentDay();

Here, `abhan.getDBInstatnce()` returns your `Database` instance which is single instance across your whole application and `getCurrentDay()` is my method, declared in `DBAdpater` which returns me a current day.

I hope this one can sort out your problem. Thanks.

Problem

I have an application uses sqlite db, at first install I check If database folder nor db file exists If not call updateDB function. but some cases for example on galaxy note 10.1 It gaves me error. on Load ; ``` this.dhn = DataHelper.getDataHelper(this); File directory = new File(Environment.getDataDirectory() + File.separator + "data" + File.separator + "XXX" + File.separator + "databases"); if(!directory.exists()) { directory.mkdirs(); updateDB(); } try { androidCheckout = this.dhn.Guid(); if(this.dhn.getSettings("dbVersion") == null || Integer.parseInt(this.dhn.getSettings("dbVersion")) != Version || !this.dhn.isTableExists("UserInfo")) { updateDB(); } } catch (SQLiteException e) { try { updateDB(); androidCheckout = this.dhn.Guid(); } catch (SQLiteException e11) { ManuelYukle(); } } public void updateDB() { this.dhn.close(); try { InputStream myInput; myInput = getAssets().open("XXX.db"); // Path to the just created empty db String outFileName = "/data/data/XXX/databases/" + "XXX.db"; // Open the empty db as the output stream FileOutputStream 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); } myOutput.flush(); myOutput.close(); myInput.close(); buffer = null; outFileName = null; this.dhn.close(); this.dhn = null; this.dhn = DataHelper.getDataHelper(this); <<<<<<<< HERE IT CRUSHS } catch (IOException e1) { e1.printStackTrace(); } } ``` DBHELPER CLASS > ``` private static DataHelper singleton; public static DataHelper getDataHelper(Context context) { if (singleton == null) { singleton = new DataHelper(context); OpenHelper openHelper = new OpenHelper(singleton.context); singleton.db = openHelper.getWritableDatabase(); } if(!singleton.db.isOpen()){ OpenHelper openHelper = new OpenHelper(singleton.context); singleton.db = openHelper.getWritableDatabase(); } singleton.context = context; return singleton; } private DataHelper(Context context) { this.context = context; } ``` ERROR LOG FILE > ``` 12-09 19:11:15.772: I/SqliteDatabaseCpp(6271): sqlite returned: error code = 11, msg = database corruption at line 48171 of [ed759d5a9e], db=/data/data/XXX/databases/XXX_db 12-09 19:11:15.772: I/SqliteDatabaseCpp(6271): sqlite returned: error code = 11, msg = database disk image is malformed, db=/data/data/XXX/databases/XXX_db 12-09 19:11:15.772: E/SqliteDatabaseCpp(6271): sqlite3_exec - Failed to set synchronous mode = 1(Normal) 12-09 19:11:15.772: I/SqliteDatabaseCpp(6271): sqlite returned: error code = 11, msg = database corruption at line 48171 of [ed759d5a9e], db=/data/data/XXX/databases/XXX_db 12-09 19:11:15.772: I/SqliteDatabaseCpp(6271): sqlite returned: error code = 11, msg = database disk image is malformed, db=/data/data/XXX/databases/XXX_db 12-09 19:11:15.772: E/SqliteDatabaseCpp(6271): CREATE TABLE android_metadata failed 12-09 19:11:15.777: E/DefaultDatabaseErrorHandler(6271): Corruption reported by sqlite on database: /data/data/XXX/databases/XXX.db 12-09 19:11:15.782: E/DefaultDatabaseErrorHandler(6271): deleting the database file: /data/data/XXX/databases/XXX.db ```

Original source