2

I'm using an external sqlite database rather than creating one in my android studio project since the database will have some already populated data in it. But I have to insert some more data as well. And when I insert any new data, it shows the new data but as I close my android app and open again to see the data, the newly inserted data through the app are somehow deleted, only prepopulated data are shown.

I am using DB browser for sqlite to create the external sqlite database and pre-populate it with some data there. In my android studio project, I added this database into my assets folder and implemented SQLiteOpenHelper class to access this database. Reading the data from the database table is a success. Now as I insert new data I can read the new data temporarily as well. Temporarily in the sense that after i close my app the new data are lost.

the table of my external sqlite database:

CREATE TABLE `table_name` (
`Id`    INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
`Content`   TEXT NOT NULL
);

SQLiteOpenHelper class:

public class ProcessExternalDBHelper {
private static final String DATABASE_NAME = "database_name.db";
private static final int DATABASE_VERSION = 1;
private static String DATABASE_PATH = "";

private static final String DATABASE_TABLE = "table_name";
private static final String KEY_ROWID = "Id";
private static final String KEY_CONTENT = "Content";

private ExternalDbHelper ourHelper;
private final Context ourContext;
private SQLiteDatabase ourDatabase;

private static class ExternalDbHelper extends SQLiteOpenHelper {

    public ExternalDbHelper(Context context) {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
        if (Build.VERSION.SDK_INT >= 17) {
            DATABASE_PATH = context.getApplicationInfo().dataDir + 
"/databases/";
        } else {
            DATABASE_PATH = "/data/data/" + context.getPackageName() + 
"/databases/";
        }
    }

    @Override
    public void onCreate(SQLiteDatabase db) {

    }

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

    }
}

public ProcessExternalDBHelper(Context context) {
    ourContext = context;
}
//for reading
public ProcessExternalDBHelper openRead() throws SQLException {
    ourHelper = new ExternalDbHelper(ourContext);
    ourDatabase = ourHelper.getReadableDatabase();
    return this;
}
//for writing
public ProcessExternalDBHelper openWrite() throws SQLException{
    ourHelper = new ExternalDbHelper(ourContext);
    ourDatabase = ourHelper.getWritableDatabase();
    return this;
}

public void close() {
    if (ourHelper != null) {
        ourHelper.close();
    }
}

//Create database in activity
public void createDatabase() throws IOException {
    createDB();
}
//Create db if not exists
private void createDB() {
    boolean dbExists = checkDatabase();
    if (!dbExists) {
        openRead();             
        try {
            this.close();
            copyDatabase();
        } catch (IOException ie) {
            throw new Error("Error copying database");
        }
    }
}

private boolean checkDatabase() {
    boolean checkDB = false;
    try {
        String myPath = DATABASE_PATH + DATABASE_NAME;
        File dbfile = new File(myPath);
        checkDB = dbfile.exists();
    } catch (SQLiteException e) {

    }
    return checkDB;
}

private void copyDatabase() throws IOException {
    InputStream myInput = null;
    OutputStream myOutput = null;
    String outFileName = DATABASE_PATH + DATABASE_NAME;

    try {
        myInput = ourContext.getAssets().open(DATABASE_NAME);
        myOutput = new FileOutputStream(outFileName);

        byte[] buffer = new byte[1024];
        int length;
        while ((length = myInput.read(buffer)) > 0) {
            myOutput.write(buffer, 0, length);
        }
        myOutput.flush();
        myOutput.close();
        myInput.close();
    } catch (IOException ie) {
        throw new Error("Copydatabase() error");
    }
}
//To show all available contents in my database
public List<Model> findallContents() {
    List<Model> mContents = new ArrayList<>();

    String[] columns = new String[]{KEY_CONTENT};
    Cursor cursor = ourDatabase.query(DATABASE_TABLE, columns, null, null, 
null, null, null);
    int iContent = cursor.getColumnIndex(KEY_CONTENT);

    for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) 
    {
        Model model= new Model();
        model.setContent(cursor.getString(iContent));

        mContents.add(model);
    }

    cursor.close();
    return mContents;
}

public void addContent(String content) {
    ContentValues contentValues = new ContentValues();
    contentValues.put(KEY_CONTENT, content);

    ourDatabase.insert(DATABASE_TABLE, null, contentValues);
    ourDatabase.close();
}

}

My Model.java class:

public class Model {
    private String mContent;

    public String getContent() {
    return mContent;
    }

    public void setContent(String content) {
        this.mContent = content;
    }
}

Finally my activity class where i read and write the data:

public class MainActivity extends AppCompatActivity {

private EditText editText_Content;
private ImageButton imageButton_Save;
private List<Model> mContentsArrayList;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    ProcessExternalDBHelper myDbHelper = new ProcessExternalDBHelper(this);
    try {
        myDbHelper.createDatabase();
    } catch (IOException ioe) {
        throw new Error("Unable to CREATE DATABASE");
    } finally {
        myDbHelper.close();
    }

    initialize();

    GetContents();

    imageButton_Save.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            if (!(editText_Content.getText().toString().trim().isEmpty())) 
            {
                SaveContents();
            } 
        }
    });
}

private void initialize() {
    editText_Content = findViewById(R.id.editText_contents);
    imageButton_Save = findViewById(R.id.imageButton_save);

    mContentsArrayList = new ArrayList<>();
}
//GetContents and show them later in my RecyclerView
private void GetContents() {
    try {
        mContentsArrayList.clear();
        ProcessExternalDBHelper autoProcess = new 
    ProcessExternalDBHelper(this);
        autoProcess.openRead();
        mContentsArrayList.addAll(autoProcess.findallContents();
        autoProcess.close();
    } catch (Exception e) {

    }
}
//For saving content into database    
private void SaveContents() {
    String content = editText_Content.getText().toString();

    try {
        ProcessExternalDBHelper autoProcess = new 
ProcessExternalDBHelper(this);
        autoProcess.openWrite();   //for writing into database
        autoProcess.addContent(content);
        autoProcess.close();
        editText_Content.getText().clear();
    } catch (Exception e) {

    }
}

}

Finally I am using DB Browser for Sqlite (ver 3.10.1), android studio (ver 3.0.1), minSdkVersion 19.

I am expecting the newly inserted data into the database to be saved and later seen even when i close my app and and restart the app later. Thank You!

Ujjwal Jung Thapa
  • 604
  • 2
  • 8
  • 31

1 Answers1

1

Your issue is that DATABASE_PATH isn't being reset and is therefore empty when createDatabase is invoked.

Therefore the check to see if the database exists fails to find the database (it's looking purely for the file database_db.db at the highest level of the file system, as such the file will not exist) and the database is copied overwriting the database that has data saved into it.

I'd suggest the following changes :-

private boolean checkDatabase() {
    File dbfile = new File(ourContext.getDatabasePath(DATABASE_NAME).getPath());
    if ( dbfile.exists()) return true;
    File dbdir = dbfile.getParentFile();
    if (!dbdir.exists()) {
        dbdir.mkdirs();
    }
    return false;
}
  • This has the advantage that if the databases directory doesn't exist that it will be created and that it relies solely on the database name for the path.
  • There is also no need for the try/catch construct.

and optionally :-

private void copyDatabase() throws IOException {
    InputStream myInput = null;
    OutputStream myOutput = null;
    String outFileName = ourContext.getDatabasePath(DATABASE_NAME).getPath(); //<<<<<<<<<< CHANGED

    try {
        myInput = ourContext.getAssets().open(DATABASE_NAME);
        myOutput = new FileOutputStream(outFileName);

        byte[] buffer = new byte[1024];
        int length;
        while ((length = myInput.read(buffer)) > 0) {
            myOutput.write(buffer, 0, length);
        }
        myOutput.flush();
        myOutput.close();
        myInput.close();
    } catch (IOException ie) {
        throw new Error("Copydatabase() error");
    }
}
  • Note if the above are applied there is no need for the SDK version check as the getDatabasePath method gets the correct path.
MikeT
  • 51,415
  • 16
  • 49
  • 68
  • Yes, I checked by initializing my DATABASE_PATH in createDatabase() as well. I really have to thank you for helping me understand my bug and showing further efficient method. IT WORKED!!! – Ujjwal Jung Thapa Dec 21 '18 at 10:14