Creating data model class for database handling - android

I was just starting to work on an database application when I realized I should implement MVC pattern as the application is quite complex and involves a number of database operations.
In regards to this, I have decided to create a separate model class for handling database operations. This class will have all methods which will return me the data after executing Sqlite command(Select for instance) OR will simply execute the SQLite command(Delete for instance). But what I want is to separate this class from Database Adapter class, where I open, create and close my database.
Let me put my concept into code :
public class DataModel
{
/*
Private members
*/
// Method to Select data from Student table
public ArrayList<String> FetchStudents (parameter 1)
{
private ArrayList<String> arrStudent;
DatabaseAdapter objDB= new DatabaseAdapter();
objDB.open();
/*
Some code
*/
objDB.close();
return arrStudent
}
//Method to delete record from Student table
public DeleteStudent(parameter 1)
{
DatabaseAdapter objDB= new DatabaseAdapter();
objDB.open();
//Some code
objDB.close();
}
/*
Rest of methods
*/
}
//DatabaseAdapterClass
private static class DatabaseHelper extends SQLiteOpenHelper {
DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
/**
* onCreate method is called for the 1st time when database doesn't exists.
*/
#Override
public void onCreate(SQLiteDatabase db) {
Log.i(TAG, "Creating DataBase: " + CREATE_STUDENT_TABLE);
db.execSQL(CREATE_STUDENT_TABLE);
}
/**
* onUpgrade method is called when database version changes.
*/
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
Log.w(TAG, "Upgrading database from version " + oldVersion + " to "
+ newVersion);
}
}
Question:
What I want to ask is this the correct approach of implementation? Is it fine if create separate class for database methods? What limitations or issues you guys think might trouble me later on? Also, is there a better way to implement the above concept?
Thanks
Stone

What you are referring to as a 'model class' is more commonly known as a data access object (DAO). Your model would usually be a set of classes that hold your data and business logic. In you case, probably a Student class having an ID, name, GPA, etc. properties. If you want to separate data access from your model, you would have your data access class (DatabaseHelper) query the database and use the data it gets to return Student objects or a List<Student>. There is really not much point in separating the data access class from the database helper, it is better to have all of your database-related code in one place.
Using model classes (only), however, may not always be practical on Android, because it has native support for getting and displaying data from a Cursor (CursorAdapter, etc.). If you want to use any of that, you would have to expose your data not as model objects but as Cursor's. As for content providers, have a look at those too, but if you don't need to expose your data to other applications, writing a ContentProvider might be overkill.
On another note, you don't want to be opening and closing the database on each query. It is actually safe to leave it open, it will be automatically closed when your app's process dies.

I do this in my application and it works wonderfully, the code is clean and it doesnt impact performance at all, especially with the hardware phones have today. I tried all of the other approaches and even used a content provider but it just over complicated things in my opinion.

android's native approach data modeling is contentproviders. Link
it kind of abstracts the type of data source as well.
i used to do it in a similar way. but again its also subjective.

Related

What is the correct way to initialize data in a lookup table using DBFlow?

I am trying to implement DBFlow for the first time and I think I might just not get it. I am not an advanced Android developer, but I have created a few apps. In the past, I would just create a "database" object that extends SQLiteOpenHelper, then override the callback methods.
In onCreate, once all of the tables have been created, I would populate any lookup data with a hard-coded SQL string: db.execSQL(Interface.INSERT_SQL_STRING);. Because I'm lazy, in onUpgrade() and onDowngrade(), I would just DROP the tables and call onCreate(db);.
I have read through the migrations documentation, which not only seems to be outdated syntactically because "database =" has been changed to "databaseName =" in the annotation, but also makes no mention of migrating from no database to version "initial". I found an issue that claims that migration 0 can be used for this purpose, but I cannot get any migrations to work at this point.
Any help would be greatly appreciated. The project is # Github.
The answer below is correct, but I believe that this Answer and Question will soon be "deprecated" along with most third-part ORMs. Google's new Room Persistence Library (Yigit's Talk) will be preferred in most cases. Although DBFlow will certainly carry on (Thank You Andrew) in many projects, here is a good place to re-direct people to the newest "best practice" because this particular question was/is geared for those new to DBFlow.
The correct way to initialize the database (akin to the SQLiteOpenHelper's onCreate(db) callback is to create a Migration object that extends BaseMigration with the version=0, then add the following to the onCreate() in the Application class (or wherever you are doing the DBFlow initialization):
FlowManager.init(new FlowConfig.Builder(this).build());
FlowManager.getDatabase(BracketsDatabase.NAME).getWritableDatabase();
In the Migration Class, you override the migrate() and then you can use the Transaction manager to initialize lookup data or other initial database content.
Migration Class:
#Migration(version = 0, database = BracketsDatabase.class)
public class DatabaseInit extends BaseMigration {
private static final String TAG = "classTag";
#Override
public void migrate(DatabaseWrapper database) {
Log.d(TAG, "Init Data...");
populateMethodOne();
populateMethodTwo();
populateMethodThree();
Log.d(TAG, "Data Initialized");
}
To populate the data, use your models to create the records and the Transaction Manager to save the models via FlowManager.getDatabase(AppDatabase.class).getTransactionManager()
.getSaveQueue().addAll(models);
To initialize data in DBFlow all you have to do is create a class for your object models that extends BaseModel and use the #Table annotation for the class.
Then create some objects of that class and call .save() on them.
You can check the examples in the library's documentation.

OrmLite inside an Android Module

I'm trying to put all the DatabaseRequests inside a module in Android to centralize all the acces to DDBB in the same place.
I'm wondering if I'm making any mistake doing that. The apps works in the right way but I'm concerned about best practices doing that.
I have an static class called DatabaseRequest where all the requests are inside, for instance:
public static void insertUser(Context context, User user) {
DataBaseHelper mDataBaseHelper = OpenHelperManager.getHelper(context, DataBaseHelper.class);
try {
Dao<User, Integer> dao = mDataBaseHelper.getUserDao();
dao.createOrUpdate(user);
} catch (SQLException e) {
e.printStackTrace();
} finally {
if (mDataBaseHelper != null) {
OpenHelperManager.releaseHelper();
}
}
}
The context param is the context of the activity that's making the request.
Is there any performance issue related with this code?
Thanks in advance ;)
No, as Gray (ORMlite creator) said in this post:
is it ok to create ORMLite database helper in Application class?
What is most important with your code is that it guarantees a single
databaseHelper instance. Each instance has it's own connection to the
database and problems happen when there are more than one (1)
connection opened to the database in a program. Sqlite handles
multiple threads using the same connection at the same time but it
doesn't handle multiple connections well and data inconsistencies may
occur.
And in your case you may have multiple connections at one time.
I can preset you my approach on how I'm using ORMlite, I have one singleton class public class DbHelper extends OrmLiteSqliteOpenHelper which takes care of creating database connection and holds all Dao fields. You will have database upgrade code there and some other stuff so consider making facade classes. In my case each facade holds one Dao object for one model class, where i keep logic for complex item retrieving (and for simple cases i just delegate it to Dao object.

Addressing multiple instances of SQLiteOpenHelper when there are multiple Content Providers for a single database

In my app, I have implemented multiple content providers for a single db, one per table, as there are a lot of tables and having the logic of all of them in a single content provider is going to be quite messy.
I followed the advice given by Simo in this link:
Content provider for multiple tables
So there is an abstract AbsShopContentProvider that has a SQLiteOpenHelper member variable. This abstract content provider is then extended by multiple content providers like Table1Provider, Table2Provider,...
So now I have one instance of my SQLiteOpenHelper per Content Provider. Will this create any issues regarding thread safety?
Is it a good idea to make this SQLiteOpenhelper variable "static" in my abstract Content Provider and create an instance of it in onCreate() of the Abstract Provider only if it is null? Will it solve the issue of having many DB helper objects?
All you need is to make sure that you share one instance of SQLiteDatabase , SQLite automatically takes care of locking for same database.
To make a database globally available, extend Application class:
public class App extends Application {
private static SQLiteDatabase db;
public static SQLiteDatabase getDb() {
return db;
}
#Override
public void onCreate() {
super.onCreate();
db = new MySQLiteOpenHelper(getApplicationContext()).getWritableDatabase();
}
}
and add it to manifest:
<application
android:name=".App"
Now, you can access the database from any Activity/Fragment/Service by calling App.getDb()

What are the advantages of using adapter, helper for creating or accessing database?

Currntly i am creating SQLite database in android using following code:
SQLiteDatabase db;
try{
SQLiteDatabase dbe = SQLiteDatabase.openDatabase("/data/data/bangla.rana.fahim/databases/dictionary", null,0);
dbe.close();
}
catch(SQLiteException e){
db = openOrCreateDatabase("dictionary", MODE_PRIVATE, null);
db.execSQL("CREATE TABLE IF NOT EXISTS LIST(wlist varchar,ex varchar);");
db.close();
}
And retrieving data using cursor like:
Cursor cc = db.rawQuery(q, null);//q is the desired query.
But i have seen many example of using helper and adapters for the very same purpose. So, my question is what are the benefits of using them?
I guess you are referring to SQLiteOpenHelper, the documentation is pretty clear:
A helper class to manage database creation and version management.
You create a subclass implementing onCreate(SQLiteDatabase),
onUpgrade(SQLiteDatabase, int, int) and optionally
onOpen(SQLiteDatabase), and this class takes care of opening the
database if it exists, creating it if it does not, and upgrading it as
necessary. Transactions are used to make sure the database is always
in a sensible state.
With this you don't have to manually create your database and take care of upgrading it. You just have to implement the two methods onCreate() and onUpgrade() with your database logic and android will make sure to call this methods when is needed. I don't know at what are you referring when you say adapter.
Well it is more concerned about software desing patters. In the SQLiteOpenHelper you do the tasks more related with creating and updating the database when user installs the app or in a db version change.
In an Adapter class which holds the previous class you usually hold a reference to the db and you have the methods to actually interact with it doing the different kind of queries (selects, inserts...).
This way you have you code well encapsulated and therefore it is much easier to maintain.

Variable database name for ContentProvider

I am creating a custom ContentProvider in Android, all the examples I find show the database name being hardcoded, instantiated like this:
public class ItemProvider extends ContentProvider {
private static String DATABASE_NAME = "xyz";
public static class ItemDatabaseHelper extends SQLiteOpenHelper {
ItemDatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
What I want to do is use a variable for the database name at runtime, I dont want to hard code the database name in the class. I have tried to find examples of doing this using the ContentProvider class, and have looked through the documentation as well. I can do this if I shed the ContentProvider class and just use a SQLiteOpenHelper class because I can pass in the database name to the constructor as a parameter but I cannot figure out if its possible for ContentProvider. Here is how I get a variable name for the database using SQLiteOpenHelper:
public static class ItemDatabaseHelper extends SQLiteOpenHelper {
ItemDatabaseHelper(Context context, String dbname) {
super(context, dbname, null, DATABASE_VERSION);
}
Can anyone help me get a variable database name for a Content Provider?
Thanks.
I've not really used ContentProviders myself, but looking at the docs I'm guessing the root of the problem is that you don't instantiate the ContentProvider yourself, but that Android does when it is needed to handle a request.
If you want the database name to be defined at runtime by your application, then you could simply use a public static variable, which you set appropriately from another part of your application. You could then reference this from your ContentProvider.
Alternatively, if you're wanting the person who requests something from the ContentProvider to be able to specify the database to query, then from the docs it looks like you could use the path of the request URI to specify the database to query.
The structure of the request URI is detailed here: http://developer.android.com/guide/topics/providers/content-providers.html#urisum and further up this page it says:
The authority is what identifies the provider, not the path; your provider can interpret the path part of the URI in any way you choose.
So as an example, I would imagine you could use an URI of the form:
content://com.example.yourprovider/DB_REF/ID
Then in your implementation of the abstract methods of ContentProvider you could parse the URI to determine the DB to use.
One word of warning though - if you are going to use this approach, then I would suggest not using the value passed in directly. It would be much better to use some kind of validation against a finite list, so that people can't just query any of your databases (if they know their name).
Hopefully that makes sense :)
First, let me say that I've looked at lots of examples for ContentProvider code on the web, and the one that ended up helping me the most was this one:
http://mobile.tutsplus.com/tutorials/android/android-sdk_content-providers/
I have a very similar situation to yours, where I want to have several differently-named databases containing vehicle fuel mileage data. Each of the names consists of a vehicle name (specified by the user) and the current year, plus the fixed text "fuel_data" to make the database filenames human-readable.
Unlike all of the examples I found, I do not create an instance of the database in the ContentProvider's onCreate method. This is because I don't yet know the vehicle name at that point, thanks to the way my code is written (and the fact that ContentProviders are instantiated so early in the Activity lifecycle).
Once I do know the vehicle name (from which I can easily construct the database name), I call a simple little method that I added to my ContentProvider class. As you can see, all it does is close the prior database (if one was open) and open the new one (using the name that I now have available).
I call this method again every time the user selects a new vehicle.
` private static FuelDatabase mDB = null;
public static void switchDatabases( Context context, String newVehicleName )
{
if ( mDB != null )
{
mbB.close();
}
mDB = new FuelDatabase( context, newVehicleName + "." + getCurrentYear( context ) );
}`

Categories

Resources