Database usage on mobile platforms may not be extensive but at some point, it is required. Android platform supports SQLite usage in your code base, but you have a lot to do! So i created this library to make database management easier.
P.S.: I strongly recommend you to use Realm if it suits your requirements though.
Create Database object(s) and add them to the DatabaseManager in order to reach out them later on by only their tags. DatabaseManager will not open your databases until you actually run a query on them, so you can add databases when you first create your databaseManager.
DatabaseManager databaseManager = new DatabaseManager();
Database localDB = new Database.Builder(Database.LOCAL, "localDbTag")
.openWith(new DbOpenHelperLocal(getApplicationContext()))
.build()
databaseManager.addDatabase(localDB);
Databases can have 2 types: Database.LOCAL
and Database.DISC
- If you create database object with
LOCAL
type, then you need to setopenWith
method to declare whichSQLiteOpenHelper
will be used while database open process. - If you create database object with
DISC
type, then you do not need to setopenWith
because it won’t be used. Instead, you need to specify thepath
of required database in Disc.
path
method is not obligatory for LOCAL
type, but if you are using getByMerged
or its derivatives, library will need your databases' path to attach it to the query, so only then you need to set the path
with LOCAL
type as well.
And if you need to declare your path with LOCAL
type, you may find the path such as:
// if local database
context.getDatabasePath(databaseName).getPath();
// if database in assets folder (via Android-Sqlite-Asset-Helper)
context.getApplicationInfo().dataDir + "/databases/" + databaseName;
P.S.: If your database is not saved in DISC
nor as it is LOCAL
, but in ASSETS
folder then i would suggest you to use Android-Sqlite-Asset-Helper-Library
.openFlags(int flags)
Via this method, you can determine database to open as readOnly or readWrite. But be aware, library will accept only SQLiteDatabase.OPEN_READWRITE
and SQLiteDatabase.OPEN_READONLY
flags. As default, library will open databases with SQLiteDatabase.OPEN_READWRITE
flag.
Create a Query object and pass that to relevant method in DatabaseManager and it will take care of the rest. Query object does not have builder pattern, but still uses chaining so you can link all methods to each other to create more readable code pattern.
new Query(databaseTag)
.set("SELECT * FROM someTable WHERE bla=? AND otherBla=?")
.withArgs("blaEquivalent", "secondBlaEquivalent")
.setListener(queryListener) // Defined below
Here, given databaseTag
needs to be same within database object so that manager can find and run the query on it. And before you run any query make sure you add required database object to the manager, otherwise it will crash.
Query object has 2 main method: set
and insert
.
insert
method is actually creates set methods inside, nothing special but it is there just because INSERT query is mostly same. Use that if only matches your requirements, if not, if you need to create a complex insert query then use set
method which accepts every query statements.
You do not have to use .withArgs
method, but be aware if you are going to type your parameters in queryText as well then you have to use inside of '
marks. Otherwise, just put ?
in place of the variables and call .withArgs(String... values)
method in same order and same count with your ?
marks.
DatabaseManager will return to QueryListener if you call one of the async methods on it, if not there is no need to set any listener.
private QueryListener queryListener = new QueryListener<CustomObject>() {
public void onComplete(Query query) { }
public void onListReceived(ArrayList<CustomObjectZ result) { }
public void onSingleItemReceived(CustomObject result) {
// This will be called if only there is a single object to return,
// if you create QueryListener with constructor has flag and pass it as true,
// then this method will not be called at all
// instead it will call onListReceived again.
}
public void noDataFound() { }
public boolean manualInjection(CustomObject object, Cursor cursor) {
return false;
}
};
QueryListener has 2 different constructor: one is default no args and the other with a boolean which indicates that the listener needs to return objects as in list, even if there is single object to return.
QueryListener injects data to required objects. So while you define your custom object, you need to have variables with same name in table’s column or you need to have @ColumnName(“Column”)
declared above your variables. So that library can deserialize it. Important: CustomOBject HAS to default no args contructor! Otherwise deserialization will not work.
ManualInjection method is used to prevent having performance lost causing by reflection, this is optional. You can override this method and handle your objects set parameters by yourself and return true, so that manager will not use reflection to set parameters.
public class CustomObject {
@ColumnName("tableColumn")
private String myValue;
private String sameWithTableColumn;
}
Finally you can call variaty of methods in DatabaseManager, just pick up which one mostly suits your statement that’s all.
public void execute(Query query);
public void executeSync(Query query);
public void select(Query query);
public ArrayList selectSync(Class clazz, Query query);
public void selectByMerged(Query query, String databaseTagToMerge);
public ArrayList selectByMergedSync(Class clazz, Query query, String databaseTagToMerge);
public void deleteAndInsert(Query deleteQuery, Query insertQuery);
public void insert(Query query);
public long insertSync(Query query);
public void update(Query query);
public int updateSync(Query query);
public void delete(Query query);
public int deleteSync(Query query);
If you are going to read/write database from DISC, do not forget to add these permissions to the manifest file.
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
- This library has no static singleton structure, because it keeps your database objects so attaching that to static instance may cause leak. Instead, create a single DatabaseManager instance in your application class and reach that out in your activities. You can see usage in sample application.
- To prevent having
java.lang.IllegalStateException: SQLiteDatabase created and never closed
it is recommended to create database object with application context, so that it will live as long as application lives and you won’t need to close it manually.
Add library dependency to your build.gradle
file:
dependencies {
compile 'com.yayandroid:DatabaseManager:1.0.3'
}
The MIT License (MIT)
Copyright (c) 2016 yayandroid
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.