Use local database in android - android

I am trying to develop an Android app. I use a local database "AndroidProject.db" which is put into the assets folder. When I try to copy the database to its correct location I encounter a NullPointer Exception. I marked the line where the Exception is happening.
Source Code:
public class DBHelper extends SQLiteOpenHelper {
public static final int VERSION = 1;
public SQLiteDatabase myDatabase;
private static final String TAG = "DBHelper";
public Context myContext;
public static final String DB_NAME = "AndroidProject.db";
public DBHelper(Context context){
super(context,DB_NAME,null,VERSION);
}
public DBHelper(Context context, String name, CursorFactory factory,
int version) {
super(context, name, factory, version);
// TODO Auto-generated constructor stub
}
public void openDatabase() {
importDatabase();
Log.i(TAG, "open database");
}
public void closeDatabase() {
myDatabase.close();
Log.i(TAG, "close database");
}
public void importDatabase() {
File f = null;
try {
// Exception occurs here
f = myContext.getDatabasePath(DB_NAME);
} catch (NullPointerException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
if (!f.exists()) {
try {
f.getParentFile().mkdirs();
InputStream is = myContext.getAssets().open("AndroidProject.db");
int size = is.available();
byte[] buffer = new byte[size];
is.read(buffer);
is.close();
FileOutputStream fos = new FileOutputStream(f);
fos.write(buffer);
fos.flush();
fos.close();
} catch (Exception e) {
Log.e("File Error", e.getMessage());
}
}
if (myDatabase == null || !myDatabase.isOpen()) {
myDatabase = SQLiteDatabase.openDatabase(f.getAbsolutePath(), null, SQLiteDatabase.OPEN_READWRITE);
}
}
public SQLiteDatabase getDatabase() {
return myDatabase;
}
#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
}
}
The error is happening here: f = myContext.getDatabasePath(DB_NAME);
Logcat:
Caused by: java.lang.NullPointerException
at fu.android.example.travelvnproject_v01.Database.DBHelper.importDatabase(DBHelper.java:59)
at fu.android.example.travelvnproject_v01.Database.DBHelper.openDatabase(DBHelper.java:42)
at fu.android.example.travelvnproject_v01.Database.DBProvider.query(DBProvider.java:38)
at fu.android.example.travelvnproject_v01.LocalActivity.onCreate(LocalActivity.java:41)
at android.app.Activity.performCreate(Activity.java:5133)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1087)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2175)

The error is happening because myContext is null. Try this:
public DBHelper(Context context, String name, CursorFactory factory,
int version) {
super(context, name, factory, version);
myContext = context;
}
EDIT:
I tested with this source code with my suggested changes and it's working fine, I only made a few other changes for convenience and I removed the unnecessary try/catch block:
public class DBHelper extends SQLiteOpenHelper {
public static final int VERSION = 1;
public SQLiteDatabase myDatabase;
private static final String TAG = "DBHelper";
public Context myContext;
public static final String DB_NAME = "AndroidProject.db";
public DBHelper(Context context){
this(context, DB_NAME, null, VERSION); // Changed this to call the other constructor for convinience
}
public DBHelper(Context context, String name, SQLiteDatabase.CursorFactory factory,
int version) {
super(context, name, factory, version);
myContext = context;
}
public void openDatabase() {
importDatabase();
Log.i(TAG, "open database");
}
public void closeDatabase() {
myDatabase.close();
Log.i(TAG, "close database");
}
public void importDatabase() {
File f = myContext.getDatabasePath(DB_NAME);
if (!f.exists()) {
try {
f.getParentFile().mkdirs();
InputStream is = myContext.getAssets().open("AndroidProject.db");
int size = is.available();
byte[] buffer = new byte[size];
is.read(buffer);
is.close();
FileOutputStream fos = new FileOutputStream(f);
fos.write(buffer);
fos.flush();
fos.close();
} catch (Exception e) {
Log.e("File Error", e.getMessage());
}
}
if (myDatabase == null || !myDatabase.isOpen()) {
myDatabase = SQLiteDatabase.openDatabase(f.getAbsolutePath(), null, SQLiteDatabase.OPEN_READWRITE);
}
}
public SQLiteDatabase getDatabase() {
return myDatabase;
}
#Override
public void onCreate(SQLiteDatabase db) {
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}

Related

I get the error android.database.sqlite.SQLiteException: no such table in android studio

I'm trying to get data from my SQLite database in the assets folder but I get the error Caused by: android.database.sqlite.SQLiteException: no such table: Product (code 1 SQLITE_ERROR): , while compiling: SELECT * FROM product.
I did the correct database copy and check the database is exists and also database opens but every time shows that error.
I also added permission WRITE_EXTERNAL_STORAGE in AndroidManifest.xml.
How can I solve this?
DatabaseSql.java
public class DatabaseSql extends SQLiteOpenHelper {
public static final String DBNAME = "sample.sqlite";
public static final String DBLOCATION = "/data/data/com.flag.flags/databases/";
private Context mContext;
private SQLiteDatabase mDatabase;
public DatabaseSql(Context context) {
super(context, DBNAME, null, 1);
this.mContext = context;
}
#Override
public void onCreate(SQLiteDatabase db) {
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
public void openDatabase() {
String dbPath = mContext.getDatabasePath(DBNAME).getPath();
if(mDatabase != null && mDatabase.isOpen()) {
return;
}
mDatabase = SQLiteDatabase.openDatabase(dbPath, null, SQLiteDatabase.OPEN_READWRITE);
}
public void closeDatabase() {
if(mDatabase!=null) {
mDatabase.close();
}
}
public List<TL_Model> getListProduct() {
TL_Model product = null;
List<TL_Model> productList = new ArrayList<>();
openDatabase();
Cursor cursor = mDatabase.rawQuery("SELECT * FROM Product", null);
cursor.moveToFirst();
while (!cursor.isAfterLast()) {
product = new TL_Model(cursor.getInt(0), cursor.getString(1), cursor.getInt(2), cursor.getString(3));
productList.add(product);
cursor.moveToNext();
}
cursor.close();
closeDatabase();
return productList;
}
}
MainActivity.java
public class TouchLearnActivity extends AppCompatActivity {
private ImageView imgBackToMain;
RecyclerView recyclerView_tl;
LinearLayoutManager linearLayoutManager;
List<TL_Model> info_list;
TL_Model model;
private DatabaseSql mDatabase;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_touch_learn);
initViews();
doClicks();
}
private void doClicks() {
imgBackToMain.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
finish();
startActivity(new Intent(TouchLearnActivity.this,MainActivity.class));
overridePendingTransition(R.anim.slide_toleft,R.anim.slide_outright);
}
});
}
private void initViews() {
mDatabase = new DatabaseSql(this);
checkdbisexists();
imgBackToMain = findViewById(R.id.imgbacktomaintl);
recyclerView_tl = findViewById(R.id.recyclertl);
recyclerView_tl.setLayoutManager(new GridLayoutManager(this,2));
info_list = mDatabase.getListProduct();
GetDataOfTL adapter = new GetDataOfTL(this,info_list);
recyclerView_tl.setAdapter(adapter);
}
private void checkdbisexists() {
File database = getApplicationContext().getDatabasePath(DatabaseSql.DBNAME);
if(false == database.exists()){
mDatabase.getReadableDatabase();
Log.i("result","Database exists");
if(CopyDb(this)){
Log.i("result","copy database successfuly");
}else{
Log.i("result","copy database failed");
return;
}
}
}
private boolean CopyDb(Context context){
try {
InputStream inputStream = context.getAssets().open(DatabaseSql.DBNAME);
String outfilename = DatabaseSql.DBLOCATION + DatabaseSql.DBNAME;
OutputStream outputStream = new FileOutputStream(outfilename);
byte[] buff = new byte[1024];
int lenght = 0;
while ((lenght = inputStream.read(buff)) > 0){
outputStream.write(buff,0,lenght);
}
outputStream.flush();
outputStream.close();
Log.d("result","DB copied");
return true;
} catch (IOException e) {
e.printStackTrace();
Log.d("result","DB copy failed" + e.getMessage());
return false;
}
}
#Override
public void finish() {
super.finish();
overridePendingTransition(R.anim.slide_toright,R.anim.slide_outleft);
}
}
Normally that happens if you are reading from an empty database. probably you are saving database in a location and reading from another location ( other location has empty data base)

How to make the data to be inside the database without the need to wait for the data to be inserted one by one?

How is it that some dictionaries such as merriam dictionary (Offline dictionary) when the application was installed , the words are there instantly, and time is not required to insert a list of words and definition into the database? I am a beginner and is currently developing an android application that consist of about 30K words and it will take around 15+ minutes for it to insert all the data into the database before the user can search for that particular data. And I am looking for a method that can fix this. Could someone please tell me a way to do it ?
Thank you
My guess is that these apps are using an already SQLite database with all the data they need already populated.
You can import populated databases to your app with something like this :
public class DataBaseAdapter {
String DB_NAME = "DBNAME.db";
String DIR = "/data/data/packageName/databases/";
String DB_PATH = DIR + DB_NAME;
private DataBaseHelper mDbHelper;
private SQLiteDatabase db;
private Context context;
public DataBaseAdapter(Context context) {
this.context = context;
mDbHelper = new DataBaseHelper(this.context);
}
class DataBaseHelper extends SQLiteOpenHelper {
private boolean createDatabase = false;
#SuppressWarnings("unused")
private boolean upgradeDatabase = false;
Context context;
public DataBaseHelper(Context context) {
super(context, DB_NAME, null, 1);
this.context = context;
}
public void initializeDataBase() {
getWritableDatabase();
if (createDatabase) {
try {
copyDataBase();
} catch (IOException e) {
throw new Error("Error copying database");
}
}
}
private void copyDataBase() throws IOException {
InputStream input = context.getAssets().open(DB_NAME);
OutputStream output = new FileOutputStream(DB_PATH);
byte[] buffer = new byte[1024];
int length;
try {
while ((length = input.read(buffer)) > 0) {
output.write(buffer, 0, length);
}
}
finally {
try {
if (output != null) {
try {
output.flush();
} finally {
output.close();
}
}
} finally {
if (input != null) {
input.close();
}
}
}
getWritableDatabase().close();
}
public void onCreate(SQLiteDatabase db) {
createDatabase = true;
}
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
upgradeDatabase = true;
}
public void onOpen(SQLiteDatabase db) {
super.onOpen(db);
}
}
public DataBaseAdapter open() {
mDbHelper.initializeDataBase();
if (db == null)
db = mDbHelper.getWritableDatabase();
return this;
}
public void close() {
db.close();
}
}
you can then add methods to get data from database and this class can be used in your activity by calling open then the method to get data then close.
Your application should include a pre-populated database for offline access with it's install. That will avoid each user having to run the INSERT step on their device.
Is there a particular reason you need to run the INSERTS post-install?

android: SQLite Exception: no suche table in existing database with three tables

I have problem which many have and I think, that I tried all solutions, but I have not found the right solution yet.
My existing database "base.sqlite3" is in "assets" folder, contains three tables.
When I want to do query, appears error, that table is not there.
(In code are possible syntax errors, cause I translated code)
public class Sqlite extends SQLiteOpenHelper {
private final Context myContext;
public SQLiteDatabase base;
private static String path ="/data/data/" + "com.example.myexample" + "/databases/";
private static String name = "base.sqlite3";
private static String p = path + name;
public Sqlite(Context context){
super(context, ime, null, 1);
this.myContext = context;
createDatabase();
}
#Override
public void onCreate(SQLiteDatabase base) {}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {}
#Override
public synchronized void close()
{
if(base != null)
base.close();
super.close();
}
public void createDatabase()
{
boolean exist1 = checkDatabase();
if(exist1){}
else
{
base = this.getReadableDatabase();
base.close();
copyDatabase();
}
}
private boolean checkDatabase()
{
SQLiteDatabase check = null;
try
{
check = SQLiteDatabase.openDatabase(p, null, SQLiteDatabase.OPEN_READONLY);
}
catch(SQLiteException e)
{ }
if(check != null)
{
check.close();
}
return check != null ? true : false;
}
private void copyDatabase()
{
InputStream dat = null;
try {
dat = myContext.getAssets().open(name);
} catch (IOException e) {
e.printStackTrace();
}
OutputStream dat2 = null;
try {
dat2 = new FileOutputStream(p);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
byte[] buffer = new byte[1024];
int length;
try {
while ((length = dat.read(buffer))>0)
{
dat2.write(buffer, 0, length);
}
} catch (IOException e) {
e.printStackTrace();
}
try {
dat2.flush();
dat2.close();
dat.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public void openDatabase()
{
base = SQLiteDatabase.openDatabase(p, null, SQLiteDatabase.OPEN_READONLY);
}
public Cursor SelectSomething(String sql)
{
base = SQLiteDatabase.openDatabase(p, null, SQLiteDatabase.OPEN_READONLY);
Cursor cursor = base.rawQuery(sql,null);
return cursor;
}
}
Thank you so much for all help!
As already was stated in the comment to this answer, the code from
this article is
" old, outdated, dreadful (concatenation to create file paths?), and problematic",
and it appears you are not the first to encounter problems with it.
Also, in the same comment to the same answer, it is proposed to use SQLiteAssetHelper. Consider trying it.

How to generate TestCases for ORMLite-Database classes in Android Development

I am working on my database layer for my android app, I would like to use testcases for this but I do not know how to solve this in android development envrionement.
I have this DBHelper class
public class DBHelper extends OrmLiteSqliteOpenHelper{
private static final String DATABASE_NAME = "pdixattach.db";
private static final int DATABASE_VERSION = 1;
private static final String TAG = DBHelper.class.getSimpleName();
private static DBHelper _helperInstance;
private Dao<Attachment, Integer> attachmentDao = null;
private Dao<User, Integer> userDao = null;
private Dao<Comment, Integer> commentDao = null;
private Dao<Job, Integer> jobDao = null;
private Dao<Target, Integer> targetDao = null;
public DBHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
#Override
public void onCreate(SQLiteDatabase db, ConnectionSource source) {
Log.i(TAG, "onCreate");
try{
TableUtils.createTable(source, Attachment.class);
TableUtils.createTable(source, User.class);
TableUtils.createTable(source, Comment.class);
TableUtils.createTable(source, Target.class);
TableUtils.createTable(source, Job.class);
} catch (Exception e){
Log.e(TAG, "error while creating tables " + e.getMessage());
throw new RuntimeException(e);
}
}
#Override
public void onUpgrade(final SQLiteDatabase db, final ConnectionSource connectionSource, final int oldVersion, final int newVersion) {
Log.i(TAG, "onUpgrade");
try {
TableUtils.dropTable(connectionSource, Attachment.class, true);
TableUtils.dropTable(connectionSource, User.class, true);
TableUtils.dropTable(connectionSource, Target.class, true);
TableUtils.dropTable(connectionSource, Job.class, true);
TableUtils.dropTable(connectionSource, Comment.class, true);
} catch (SQLException e) {
Log.e(TAG, "error while upgrading tables " + e.getMessage());
throw new RuntimeException(e);
}
// after we drop the old databases, we create the new ones
onCreate(db, connectionSource);
}
public Dao<Attachment, Integer> getAttachmentDao() throws SQLException {
if (this.attachmentDao == null) {
this.attachmentDao = getDao(Attachment.class);
}
return this.attachmentDao;
}
public Dao<User, Integer> getUserDao() throws SQLException {
if (this.userDao == null) {
this.userDao = getDao(User.class);
}
return this.userDao;
}
public Dao<Comment, Integer> getCommentDao() throws SQLException {
if (this.commentDao == null) {
this.commentDao = getDao(User.class);
}
return this.commentDao;
}
public Dao<Target, Integer> getTargetDao() throws SQLException {
if (this.targetDao == null) {
this.targetDao = getDao(User.class);
}
return this.targetDao;
}
public Dao<Job, Integer> getJobDao() throws SQLException {
if (this.jobDao == null) {
this.jobDao = getDao(User.class);
}
return this.jobDao;
}
/**
* Close the database connections and clear any cached DAOs.
*/
#Override
public void close() {
super.close();
_helperInstance = null;
this.attachmentDao = null;
this.commentDao = null;
this.jobDao = null;
this.targetDao = null;
this.userDao = null;
}
With this DBManager:
public class DBManager {
private Dao<User,Integer> userDao;
private Dao<Attachment,Integer> attachmentDao;
private Dao<Target,Integer> targetDao;
private Dao<Comment,Integer> commentDao;
private Dao<Job,Integer> jobDao;
private DBHelper helper;
private static DBManager uniqueInstance;
private static final String TAG = DBManager.class.getSimpleName();
public DBManager(Context context) {
helper = new DBHelper(context);
}
public static void init(Context context){
if (uniqueInstance == null) {
uniqueInstance = new DBManager(context);
}
}
public static synchronized DBManager getInstance(){
return uniqueInstance;
}
private void injectDBHelper(DBHelper dbhelper) {
if (this.helper == null)
this.helper = dbhelper;
else
Log.d(TAG, "DBHelper already available in DBManager");
}
public boolean addUser(User u){
boolean retVal = false;
if (u == null){
throw new IllegalArgumentException("user must not be null");
}
try {
helper.getUserDao().create(u);
retVal = true;
} catch (SQLException e) {
Log.e(TAG, "error while adding user to db " + e.getMessage());
}
return retVal;
}
public boolean addServiceEndpoint(String endpoint) {
boolean retVal = false;
if (endpoint == null){
throw new IllegalArgumentException("endpoint must not be null");
}
try {
Target t = new Target(endpoint);
int result = helper.getTargetDao().create(t);
retVal = (result == 1);
} catch (SQLException e) {
Log.e(TAG, "error while adding target to db, with service endpoint " + endpoint + "error" + e.getMessage());
}
return retVal;
}
I want to generate testcase for the addUser method, can someone help me with that. How can I achieve this in android development envrionment?
Thanks

Where is my database file created

This is my file dataSqliteHelper and when I run the first time, the data file is created but I don't know where is it to get it and open it with a tool and view the file.
public class DataSQLiteHelper extends OrmLiteSqliteOpenHelper {
public static final String DATABASE_NAME = "ventasdb.db";
private static final int DATABASE_VERSION = 1;
private Context mContext;
private Dao<Customer, Integer> customerDao;
public DataSQLiteHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
#Override
public void onCreate(SQLiteDatabase db, ConnectionSource conections) {
try {
TableUtils.createTable(connectionSource, Customer.class);
} catch (Exception e) {
Log.e(DataSQLiteHelper.class.getName(), "Can't create database", e);
throw new RuntimeException(e);
}
}
#Override
public void onUpgrade(SQLiteDatabase db, ConnectionSource connectionSource,
int oldVersion, int newVersion) {
try {
TableUtils.dropTable(connectionSource, Customer.class, true);
} catch (SQLException e) {
throw new RuntimeException(e);
} catch (java.sql.SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* Returns the Database Access Object (DAO) for our UserData class. It will
* create it or just give the cached value.
*/
public Dao<Customer, Integer> getCustomerDao() {
if (customerDao == null) {
try {
customerDao = getDao(Customer.class);
} catch (java.sql.SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return customerDao;
}
public boolean updateCustomer(Customer p) {
boolean ret = false;
if (customerDao != null) {
try {
customerDao = getDao(Customer.class);
UpdateBuilder<Customer, Integer> updateBuilder = customerDao
.updateBuilder();
updateBuilder.updateColumnValue("name", "PIRIPIPI"); // p.getName());
updateBuilder.updateColumnValue("cel", p.getCel());
updateBuilder.updateColumnValue("email", p.getEmail());
updateBuilder.updateColumnValue("address", p.getAddress());
updateBuilder.updateColumnValue("City", p.getCity());
// but only update the rows where the description is some value
updateBuilder.where().eq("customerID", 0);
// actually perform the update
customerDao.update(p);
customerDao.refresh(p);
} catch (Exception e) {
ret = false;
e.printStackTrace();
}
}
return ret;
}
/**
* Close the database connections and clear any cached DAOs.
*/
#Override
public void close() {
super.close();
}
}
with this line I know that I give the file name
super(context, DATABASE_NAME, null, DATABASE_VERSION);
but where is it in the storage of the device?
By the way , can I change the path to store the file in the sd card ?
it will be stored at
/data/data/[package name]/databases
But unless your phone is rooted you cannot browse to it using file explorer or adb shell
It is saved here (as nandeesh says)
/data/data/[package name]/databases
You can only access it on a phone if it is rooted. Or you can install the app on an emulator, start up the DDMS tool and view the database file there.

Categories

Resources