External database access, my app crashes - java

Yes I have searched for many solutions for days. My still persisting problem is my app crashes at start when I am trying to access an external database (created through "DB Browser for Sqlite" named "test.db").
The sole purpose is of course to prepopulate my app with some data.
I have kept the database file on assets folder in android studio. Finally I have implemented a helper class to access the database.
Here is the helper class:
public class DataBaseHelper extends SQLiteOpenHelper {
private static final String DATABASE_NAME = "test.db";
private static final int DATABASE_VERSION = 1;
private static String DATABASE_PATH = "";
private SQLiteDatabase myDataBase;
private final Context myContext;
public DataBaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
this.myContext = context;
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 void createDatabase() throws IOException {
createDB();
}
private void createDB() {
boolean dbExists = checkDatabase();
if (dbExists) {
//do nothing
} else {
this.getReadableDatabase();
try {
copyDatabase();
} catch (IOException ie) {
throw new Error("Error copying database");
}
}
}
private boolean checkDatabase() {
SQLiteDatabase checkDB = null;
try {
String myPath = DATABASE_PATH + DATABASE_NAME;
checkDB = SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.OPEN_READONLY);
checkDB.setLocale(Locale.getDefault());
} catch (SQLiteException e) {
throw new Error("SQLite exception");
}
if (checkDB != null) {
checkDB.close();
}
return checkDB != null;
}
private void copyDatabase() throws IOException {
InputStream myInput = null;
OutputStream myOutput = null;
String outFileName = DATABASE_PATH + DATABASE_NAME;
try{
myInput = myContext.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 run error ");
}
}
#Override
public synchronized void close() {
if(myDataBase != null){
myDataBase.close();
}
super.close();
}
}
In the Main activity I have just called the createDatabase() method of the helper class. The code being below:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DataBaseHelper myDbHelper = new DataBaseHelper(this);
try{
myDbHelper.createDatabase();
}catch (IOException ioe){
throw new Error("Unable to CREATE DATABASE");
}
}
}
The logcat indicates the problem as:
AndroidRuntime: FATAL EXCEPTION: main java.lang.Error: SQLite
exception at DataBaseHelper.checkDatabase(DataBaseHelper.java:79) at
DataBaseHelper.createDB(DataBaseHelper.java:59) at
DataBaseHelper.createDatabase(DataBaseHelper.java:55) at
MainActivity.onCreate(MainActivity.java:18)
which points to my checkDatabase() method. But now I am not able to sort out the problem.
I am using Android Studio 3.0.1, DB Browser for Sqlite 3.10.1, Min API level used 17.
Please Help!

Try This
public static final String DATABASE_NAME = "abc.db";
public final static String DATABASE_PATH = "/data/data/"+ PACKAGE_NAME +
"/databases/";
public static final int DATABASE_VERSION = 1;
public void createDatabase() {
boolean dbExist1 = checkDataBase();
if (!dbExist1) {
this.getReadableDatabase();
try {
this.close();
copyDataBase();
} catch (IOException e) {
throw new Error("Error copying database");
}
}
}
// Check database already exist or not
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;
}
// Copies your database from your local assets-folder to the just created
// empty database in the system folder
public void copyDataBase() throws IOException {
String outFileName = DATABASE_PATH + DATABASE_NAME;
OutputStream myOutput = new FileOutputStream(outFileName);
InputStream myInput = mContext.getAssets().open(DATABASE_NAME);
byte[] buffer = new byte[1024];
int length;
while ((length = myInput.read(buffer)) > 0) {
myOutput.write(buffer, 0, length);
}
myInput.close();
myOutput.flush();
myOutput.close();
}

Related

How to get data from a sqllite database and store it in ListView

I have a data base I need to read data from it and view it in a list view it contain some tables from them a table named "main_categories" which has one field called "category_name" which is the primary key
this is the DataAdapter:
public DataAdapter(Context context) {
this.mContext = context;
mDbHelper = new DataBaseHelper(mContext);
}
public DataAdapter createDatabase() throws SQLException {
try {
mDbHelper.createDataBase();
} catch (IOException mIOException) {
Log.e(TAG, mIOException.toString() + " UnableToCreateDatabase");
throw new Error("UnableToCreateDatabase");
}
return this;
}
public DataAdapter open() throws SQLException {
try {
mDbHelper.openDataBase();
mDbHelper.close();
mDb = mDbHelper.getReadableDatabase();
} catch (SQLException mSQLException) {
Log.e(TAG, "open >>" + mSQLException.toString());
throw mSQLException;
}
return this;
}
public void close() {
mDbHelper.close();
}
public Cursor getTestData() {
try {
String sql = "SELECT * FROM myTable";
Cursor mCur = mDb.rawQuery(sql, null);
if (mCur != null) {
mCur.moveToNext();
}
return mCur;
} catch (SQLException mSQLException) {
Log.e(TAG, "getTestData >>" + mSQLException.toString());
throw mSQLException;
}
}
}
and this is the DataBaseHelper:
public class DataBaseHelper extends SQLiteOpenHelper
{
private static String TAG = "DataBaseHelper"; // Tag just for the LogCat window
//destination path (location) of our database on device
private static String DB_PATH = "";
private static String DB_NAME ="my_knowledge";// Database name
private SQLiteDatabase mDataBase;
private final Context mContext;
public DataBaseHelper(Context context)
{
super(context, DB_NAME, null, 1);// 1? Its database Version
if(android.os.Build.VERSION.SDK_INT >= 17){
DB_PATH = context.getApplicationInfo().dataDir + "/databases/";
}
else
{
DB_PATH = context.getApplicationInfo().dataDir + "/databases/";
}
this.mContext = context;
}
public void createDataBase() throws IOException
{
//If the database does not exist, copy it from the assets.
boolean mDataBaseExist = checkDataBase();
if(!mDataBaseExist)
{
this.getReadableDatabase();
this.close();
try
{
//Copy the database from assests
copyDataBase();
Log.e(TAG, "createDatabase database created");
}
catch (IOException mIOException)
{
throw new Error("ErrorCopyingDataBase");
}
}
}
//Check that the database exists here: /data/data/your package/databases/Da Name
private boolean checkDataBase()
{
File dbFile = new File(DB_PATH + DB_NAME);
//Log.v("dbFile", dbFile + " "+ dbFile.exists());
return dbFile.exists();
}
//Copy the database from assets
private void copyDataBase() throws IOException
{
InputStream mInput = mContext.getAssets().open(DB_NAME);
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();
}
//Open the database, so we can query it
public boolean openDataBase() throws SQLException
{
String mPath = DB_PATH + DB_NAME;
//Log.v("mPath", mPath);
mDataBase = SQLiteDatabase.openDatabase(mPath, null, SQLiteDatabase.CREATE_IF_NECESSARY);
//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 sqLiteDatabase) {
}
#Override
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {
}
}
and this is the main activity for now:
public class MainActivity extends AppCompatActivity {
SQLiteDatabase sqLiteDatabase;
private static String DB_NAME ="my_knowledge"; // Database name
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ListView list = findViewById(R.id.main_list);
DataAdapter mDbHelper = new DataAdapter(this);
mDbHelper.createDatabase();
mDbHelper.open();
Cursor testdata = mDbHelper.getTestData();
mDbHelper.close();
}
}
I want to know a way to store the data in the tables of the array (for example "main_categories") and view them with the list view
Depending on your table column type
List<String> temp;
testdata.moveToFirst();
do {
temp.add(testdata.getString(0));
} while (testdata.moveToNext());
Your cursor testdata has the first row in testdata.moveToFirst(); and each column is associated with column index i.e. 0, 1 etc.
testdata.moveToNext(); will have successive rows.
A couple of things:
First of, I would consider adding a query method to your DataBaseHelper class instead of using a rawQuery, something like:
Cursor query(String table, String[] projection, String where, String orderBy) {
return getReadableDatabase().query(table, projection, where, null, null, null, orderBy);
}
You can call the query method inside mDbHelper.getTestData() and use the Cursor object to populate your list.
Take a look at using a Cursor Loader?
to do get the data out of the cursor and into your adapter.

Sqlite: Updating is done but on retreving, value returned is null

I'm using an existing database. For a table in that database, I'm updating a columns value of a particular row identified by 'chapter' and 'verse' by some user input(String). The updating is successful, however on retrieving the updated value it shows null.
FragmentFour.java
public class FragmentFour extends Fragment {
DataBaseHelper dbHelper;
#Override
public View onCreateView(final LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
......
dbHelper = new DataBaseHelper(getActivity());
......
}
public void someFunction(){
String notes = dbHelper.getNotes("SomeBookName",some_chapter,some_verse);
}
}
DataBaseHelper.java
public class DataBaseHelper extends SQLiteOpenHelper{
private static String TAG = "DataBaseHelper"; // Tag just for the LogCat window destination path (location) of our database on device
private static String DB_PATH = "";
private static String DB_NAME ="zypnt.sqlite";// Database name
private SQLiteDatabase mDataBase;
private final Context mContext;
public DataBaseHelper(Context context)
{
super(context, DB_NAME, null, 1);// 1? its Database Version
if(android.os.Build.VERSION.SDK_INT >= 17){
DB_PATH = context.getApplicationInfo().dataDir + "/databases/";
}
else
{
DB_PATH = "/data/data/" + context.getPackageName() + "/databases/";
}
this.mContext = context;
}
#Override
public void onCreate(SQLiteDatabase db) {
// TODO Auto-generated method stub
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// TODO Auto-generated method stub
}
public void createDataBase() throws IOException
{
//If database not exists copy it from the assets
boolean mDataBaseExist = checkDataBase();
if(!mDataBaseExist)
{
this.getReadableDatabase();
this.close();
try
{
//Copy the database from assests
copyDataBase();
Log.e(TAG, "createDatabase database created");
}
catch (IOException mIOException)
{
throw new Error("ErrorCopyingDataBase");
}
}
}
//Check that the database exists here: /data/data/your package/databases/Da Name
private boolean checkDataBase()
{
File dbFile = new File(DB_PATH + DB_NAME);
//Log.v("dbFile", dbFile + " "+ dbFile.exists());
return dbFile.exists();
}
//Copy the database from assets
private void copyDataBase() throws IOException
{
InputStream mInput = mContext.getAssets().open(DB_NAME);
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();
}
//Open the database, so we can query it
public boolean openDataBase() throws SQLException
{
String mPath = DB_PATH + DB_NAME;
//Log.v("mPath", mPath);
mDataBase = SQLiteDatabase.openDatabase(mPath, null, SQLiteDatabase.CREATE_IF_NECESSARY);
//mDataBase = SQLiteDatabase.openDatabase(mPath, null, SQLiteDatabase.NO_LOCALIZED_COLLATORS);
return mDataBase != null;
}
#Override
public synchronized void close()
{
if(mDataBase != null)
mDataBase.close();
super.close();
}
public String getNotes(String book,String chapter,String verse){
SQLiteDatabase mDb = this.getWritableDatabase();
String notes = "";
try{
Cursor c = mDb.rawQuery("SELECT footnotes FROM " + book + " WHERE chapter="+chapter+" and verse="+verse+"", null);
if(c.getCount()<=0)
return notes;
else {
c.moveToFirst();
notes = c.getString(0);
c.close();
}
} catch (Exception e) {
Log.e("getCrossReferences", e.getMessage());
}
mDb.close();
return notes;
}
public Boolean setNotes(String book,String chapter,String verse,String note){
SQLiteDatabase mDb = this.getWritableDatabase();
Boolean flag = false;
try{
Cursor c = mDb.rawQuery("UPDATE "+book+" SET footnotes='" + note + "' WHERE chapter="+chapter+" and verse="+verse+"", null);
c.close();
flag = true;
} catch (Exception e) {
Log.e("getCrossReferences", e.getMessage());
}
mDb.close();
return flag;
}
}
Try this change:
public Boolean setNotes(String book,String chapter,String verse,String note){
SQLiteDatabase mDb = this.getWritableDatabase();
Boolean flag = false;
try{
Cursor c = mDb.rawQuery("UPDATE "+book+" SET footnotes='" + note + "' WHERE chapter="+chapter+" and verse="+verse+"", null);
c.moveToFirst();
c.close();
flag = true;
} catch (Exception e) {
Log.e("getCrossReferences", e.getMessage());
}
mDb.close();
return flag;
}
Try this
if (c != null ) {
if (c.moveToFirst()) {
return c.getString(c.getColumnIndex("footnotes"));
}
}
c.close();

onUpgrade() and onCreate() method do not invoke when creating a new version of database in SQLiteOpenHelper

I am trying to create a new version of database in my android app. But although I change the version of database from previous version (2) to a new version (3) it doesn't invoke onUpgrade() and onCreate() . It just invoke three times the constructor. I do not understand why constructor invoked three times and also why onUpgrade() and onCreate() did not invoke?
I also tried with new database version code but result is same.
Here is my code.
public class DatabaseHelper extends SQLiteOpenHelper {
private static String PACKAGE_NAME;
private static String DB_PATH;
private static String DB_NAME = "mydata.db";
private SQLiteDatabase myDataBase;
private final Context myContext;
public DatabaseHelper(Context context) {
super(context, DB_NAME, null, 3);
this.myContext = context;
Log.e("UPDATED3", "CONSTRUCTOR");
PACKAGE_NAME = myContext.getPackageName();
DB_PATH = "/data/data/" + PACKAGE_NAME + "/databases/";
}
public void createDataBase() throws IOException {
boolean dbExist = checkDataBase();
if (dbExist) {
// do nothing - database already exist
} else {
// By calling this method and empty database will be created into
// the default system path
// of your application so we are gonna be able to overwrite that
// database with our database.
this.getReadableDatabase();
try {
copyDataBase();
} catch (IOException e) {
throw new Error("Error copying database");
}
}
}
private boolean checkDataBase() {
SQLiteDatabase checkDB = null;
try {
String myPath = DB_PATH + DB_NAME;
checkDB = SQLiteDatabase.openDatabase(myPath, null,
SQLiteDatabase.OPEN_READWRITE);
} catch (SQLiteException e) {
// database does't exist yet.
}
if (checkDB != null) {
checkDB.close();
}
return checkDB != null ? true : false;
}
private void copyDataBase() throws IOException {
// Open your local db as the input stream
InputStream myInput = myContext.getAssets().open(DB_NAME);
// Path to the just created empty db
String outFileName = DB_PATH + DB_NAME;
// Open the empty db as the output stream
OutputStream 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);
}
// Close the streams
myOutput.flush();
myOutput.close();
myInput.close();
}
public void openDataBase() throws SQLException {
// Open the database
String myPath = DB_PATH + DB_NAME;
myDataBase = SQLiteDatabase.openDatabase(myPath, null,
SQLiteDatabase.OPEN_READWRITE);
}
#Override
public synchronized void close() {
if (myDataBase != null)
myDataBase.close();
super.close();
}
#Override
public void onCreate(SQLiteDatabase db) {
Log.e("UPDATED3", "ONCREATE");
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
Log.e("UPDATED3", "UPDATED THE DATABASE");
}
}
I use my database this(showing below) way in any activity.
DatabaseHelper databaseHelper = new DatabaseHelper(getApplicationContext());
try {
databaseHelper.createDataBase();
databaseHelper.openDataBase();
} catch (IOException e) {
Toast.makeText(getApplicationContext(), "Error: " + e.getMessage(),
Toast.LENGTH_LONG).show();
e.printStackTrace();
}

Database onUpgrade method is never called

I'm trying to upgrade my database from version 1 to version 2. I'm assigning DATABASE_VERSION = 2 (first version was assigned too) but onUpgrade never called.
May be there is an obvious mistake in the code, but I can't see it beacause I'm trying to solve this problem for a long time.
Here is the code of database helper class:
public class DatabaseHelper extends SQLiteOpenHelper {
private static final int DATABASE_VERSION = 2;
public static String DB_PATH;
public static String DB_NAME = "db.sqlite3";
public SQLiteDatabase database;
public final Context context;
public DatabaseHelper(Context context) {
super(context, DB_NAME, null, DATABASE_VERSION);
this.context = context;
File direct = new File(Environment.getExternalStorageDirectory()
+ "/.test");
if (!direct.exists()) {
if (direct.mkdir())
;
}
DB_PATH = Environment.getExternalStorageDirectory().getPath()
+ "/.test/";
}
public void createDataBase() {
boolean dbExist = checkDataBase();
if (!dbExist) {
try {
copyDataBase();
} catch (IOException e) {
Log.e(this.getClass().toString(), "Copying error");
throw new Error("Error copying database!");
}
}
}
private boolean checkDataBase() {
SQLiteDatabase checkDb = null;
try {
String path = DB_PATH + DB_NAME;
checkDb = SQLiteDatabase.openDatabase(path, null,
SQLiteDatabase.OPEN_READONLY);
} catch (SQLException e) {
Log.e(this.getClass().toString(), "Error while checking db");
}
if (checkDb != null) {
checkDb.close();
}
return checkDb != null;
}
private void copyDataBase() throws IOException {
InputStream externalDbStream = context.getAssets().open(
"databases/" + 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();
}
public SQLiteDatabase openDataBase() throws SQLException {
String path = DB_PATH + DB_NAME;
if (database == null) {
createDataBase();
database = SQLiteDatabase.openDatabase(path, null,
SQLiteDatabase.OPEN_READONLY);
}
return database;
}
// some unimportant methods
#Override
public void onCreate(SQLiteDatabase db) {
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
Log.w("myLogs", " --- onUpgrade database --- ");
}
In Activity I call database like this:
DatabaseHelper dbOpenHelper = new DatabaseHelper(this);
SQLiteDatabase database = dbOpenHelper.openDataBase();
Where is my mistake?
Help, please.
UPD: database.getVersion() returns 0
Updated openDataBase() method (it's working):
public SQLiteDatabase openDataBase() throws SQLException {
String path = DB_PATH + DB_NAME;
if (database == null) {
createDataBase();
database = SQLiteDatabase.openDatabase(path, null,
SQLiteDatabase.OPEN_READWRITE);
this.getWritableDatabase();
}
return database;
}
Local database version will always be 0 and onUpgrade will not be called, because you never called getWritableDatabase/getReadableDatabase, which will bump version and return local db.
So you need:
make call getReadableDatabase(); in your contructor/oncreate, just to trigger process, in case db version is changed
or
manually check sdcard version, db.getVersion(); compare to current version - DATABASE_VERSION. And do what ever you need to do - upgrade or downgrade.

Copying database works on emulator but not on device

This works on the emulator but not on my phone. At least it seems so because it does not find the table when I query it on the phone.
This my class that inherits from SQLiteOpenHelper
public class DBHelper extends SQLiteOpenHelper {
private final static String DB_NAME = "klb_db.sqlite";
private final static int DB_VERSION = 1;
private String dbPath;
private Context context;
public DBHelper(Context context) {
super(context, DB_NAME, null, DB_VERSION);
this.context = context;
dbPath = "/" + Environment.getDataDirectory() + "/data/" + context.getPackageName() + "/databases/";
}
public void initializeDatabase() {
try {
File file = new File(dbPath + DB_NAME);
if (!file.exists()) {
InputStream inputStream = context.getAssets().open(
"klb_db.sqlite");
OutputStream outputStream = new FileOutputStream(file);
byte[] buffer = new byte[1024];
int length;
while ((length = inputStream.read(buffer)) > 0) {
outputStream.write(buffer, 0, length);
}
inputStream.close();
outputStream.close();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
In dbadapter, open method:
public DBAdapter open() {
dbHelper.initializeDatabase();
db = dbHelper.getWritableDatabase();
return this;
}
In activity that uses it:
#Override
protected void onStart() {
super.onStart();
QuizDAO quizDAO = new QuizDAO(this);
quizDAO.open();
Cursor cursor = quizDAO.getQuestion(10);
Toast.makeText(this, cursor.getString(1), Toast.LENGTH_LONG).show();
}
try to increase you bytes
byte[] buffer = new byte[1024];
to
byte[] buffer = new byte[2048];
EDITED
#Override
protected void onStart() {
super.onStart();
QuizDAO quizDAO = new QuizDAO(this);
quizDAO.open();
Cursor cursor = quizDAO.getQuestion(10);
cursor.moveToFirst()
Toast.makeText(this, cursor.getString(1), Toast.LENGTH_LONG).show();
}

Categories