SQLite is a relational database management system (RDBMS) contained in a C library. In Android, SQLiteDatabase is the class that manages the actual database file. It provides methods to execute SQL commands (Create, Read, Update, Delete).
To use it properly, we don't just create an SQLiteDatabase object directly. Instead, we create a helper class that extends SQLiteOpenHelper. This helper manages:
- Creating the database (if it doesn't exist).
- Opening connections.
- Upgrading the structure (if you change the version number).
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import androidx.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;
public class MyDatabaseHelper extends SQLiteOpenHelper {
// Database Info
private static final String DB_NAME = "MyCollege.db";
private static final int DB_VERSION = 1;
// Table Info
private static final String TABLE_NAME = "students";
private static final String COL_ID = "id";
private static final String COL_NAME = "name";
private static final String COL_GPA = "gpa";
public MyDatabaseHelper(@Nullable Context context) {
super(context, DB_NAME, null, DB_VERSION);
}
// 1. CREATE TABLE (Runs once when app is installed/first run)
@Override
public void onCreate(SQLiteDatabase db) {
// create all required tables
String createTableQuery = "CREATE TABLE " + TABLE_NAME + " (" +
COL_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
COL_NAME + " TEXT, " +
COL_GPA + " REAL)";
db.execSQL(createTableQuery);
}
// 2. UPGRADE TABLE (Runs if you change DB_VERSION)
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// mention drop for all tables existing
db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME);
onCreate(db);
}
// =================================================================
// C R U D O P E R A T I O N S
// =================================================================
// --- INSERT ---
public boolean addStudent(String name, double gpa) {
SQLiteDatabase db = this.getWritableDatabase();
// METHOD A: Android Helper Way (Safe & Easy)
ContentValues values = new ContentValues();
values.put(COL_NAME, name);
values.put(COL_GPA, gpa);
// params: Table, NullColHack, Values
// returns -1 if failed, or the new Row ID if successful
long result = db.insert(TABLE_NAME, null, values);
return result != -1;
/* // METHOD B: Raw SQL Way
// Note: Harder to handle standard quotes ' inside names (SQL Injection risk)
String query = "INSERT INTO " + TABLE_NAME + " (" + COL_NAME + ", " + COL_GPA + ") VALUES ('" + name + "', " + gpa + ")";
db.execSQL(query);
return true;
*/
}
// --- UPDATE ---
public boolean updateStudentGPA(int id, double newGpa) {
SQLiteDatabase db = this.getWritableDatabase();
// METHOD A: Android Helper Way
ContentValues values = new ContentValues();
values.put(COL_GPA, newGpa);
// params: Table, ContentValues, WhereClause, WhereArgs array
int rowsAffected = db.update(TABLE_NAME, values, COL_ID + " = ?", new String[]{String.valueOf(id)});
return rowsAffected > 0;
/* // METHOD B: Raw SQL Way
String query = "UPDATE " + TABLE_NAME + " SET " + COL_GPA + " = " + newGpa + " WHERE " + COL_ID + " = " + id;
db.execSQL(query);
return true;
*/
}
// --- DELETE ---
public boolean deleteStudent(int id) {
SQLiteDatabase db = this.getWritableDatabase();
// METHOD A: Android Helper Way
// params: Table, WhereClause, WhereArgs array
int rowsDeleted = db.delete(TABLE_NAME, COL_ID + " = ?", new String[]{String.valueOf(id)});
return rowsDeleted > 0;
/* // METHOD B: Raw SQL Way
String query = "DELETE FROM " + TABLE_NAME + " WHERE " + COL_ID + " = " + id;
db.execSQL(query);
return true;
*/
}
// --- GET ALL (READ) ---
public Cursor getAllStudents() {
SQLiteDatabase db = this.getReadableDatabase();
// METHOD A: Android Helper Way (query)
// Table, Columns (null=all), Selection, SelectionArgs, GroupBy, Having, OrderBy
return db.query(TABLE_NAME, null, null, null, null, null, COL_ID + " DESC");
/*
// METHOD B: Raw SQL Way (rawQuery)
return db.rawQuery("SELECT * FROM " + TABLE_NAME + " ORDER BY " + COL_ID + " DESC", null);
*/
}
public ArrayList<Student> getStudentList() {
ArrayList<Student> studentList = new ArrayList<>();
// 1. Get the Cursor
Cursor cursor = getAllStudents();
// Safety Check
if (cursor == null) return studentList;
// 2. Get Column Indices ONCE (Clean & Efficient)
int idIdx = cursor.getColumnIndex(COL_ID);
int nameIdx = cursor.getColumnIndex(COL_NAME);
int gpaIdx = cursor.getColumnIndex(COL_GPA);
// 3. FOR LOOP
// Start: moveToFirst()
// Stop: isAfterLast() (Returns true when we go past the last row)
// Step: moveToNext()
for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
int id = cursor.getInt(idIdx);
String name = cursor.getString(nameIdx);
double gpa = cursor.getDouble(gpaIdx);
studentList.add(new Student(id, name, gpa));
}
// 4. Always close!
cursor.close();
return studentList;
}
// --- GET SPECIFIC (READ with Condition) ---
public Cursor getStudentByName(String searchName) {
SQLiteDatabase db = this.getReadableDatabase();
// METHOD A: Android Helper Way
// Condition: name = ?
return db.query(TABLE_NAME, null, COL_NAME + " = ?", new String[]{searchName}, null, null, null);
/*
// METHOD B: Raw SQL Way
return db.rawQuery("SELECT * FROM " + TABLE_NAME + " WHERE " + COL_NAME + " = ?", new String[]{searchName});
*/
}
// --- GET SPECIFIC (Multiple Conditions) ---
public Cursor getSmartStudents(String name, double minGpa) {
SQLiteDatabase db = this.getReadableDatabase();
// Condition: name = ? AND gpa > ?
String selection = COL_NAME + " = ? AND " + COL_GPA + " > ?";
String[] selectionArgs = { name, String.valueOf(minGpa) };
return db.query(TABLE_NAME, null, selection, selectionArgs, null, null, null);
}
}import android.database.Cursor;
import android.os.Bundle;
import android.util.Log;
import androidx.appcompat.app.AppCompatActivity;
import java.util.ArrayList;
public class MainActivity extends AppCompatActivity {
MyDatabaseHelper dbHelper;
private static final String TAG = "DB_TEST";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
dbHelper = new MyDatabaseHelper(this);
// 1. INSERT DATA
Log.d(TAG, "--- Inserting Data ---");
dbHelper.addStudent("Ali", 3.2);
dbHelper.addStudent("Sara", 3.9);
dbHelper.addStudent("John", 2.5);
// 2. UPDATE DATA (Update Ali's GPA)
Log.d(TAG, "--- Updating Ali's GPA to 4.0 ---");
// Assuming Ali has ID 1 (AutoIncrement starts at 1)
dbHelper.updateStudentGPA(1, 4.0);
// 3. DELETE DATA (Delete John)
Log.d(TAG, "--- Deleting John (ID 3) ---");
dbHelper.deleteStudent(3);
// 4. GET ALL STUDENTS (Using your ArrayList function)
Log.d(TAG, "--- Reading All Students ---");
ArrayList<Student> list = dbHelper.getStudentList();
for (Student s : list) {
Log.d(TAG, "ID: " + s.id + ", Name: " + s.name + ", GPA: " + s.gpa);
}
// 5. GET SPECIFIC STUDENT (Using Cursor function)
Log.d(TAG, "--- Searching for 'Sara' ---");
Cursor cursor = dbHelper.getStudentByName("Sara");
if (cursor != null && cursor.moveToFirst()) {
String name = cursor.getString(cursor.getColumnIndex("name"));
double gpa = cursor.getDouble(cursor.getColumnIndex("gpa"));
Log.d(TAG, "Found: " + name + " with GPA: " + gpa);
cursor.close();
}
}
}| Operation | Method Name | Return Type | Syntax / Parameters | Example (Single & Multi Condition) |
|---|---|---|---|---|
| INSERT | db.insert() |
long(New Row ID or -1) |
Table: String NullColHack: String (pass null) Values: ContentValues |
insert("users", null, contentValues) |
| UPDATE | db.update() |
int(Count of rows updated) |
Table: String Values: ContentValues WhereClause: String ("id=?") WhereArgs: String[] |
Single: "id=?", new String[]{"1"}Multi: "age > ? AND city = ?", new String[]{"18", "Lahore"} |
| DELETE | db.delete() |
int(Count of rows deleted) |
Table: String WhereClause: String WhereArgs: String[] |
Single: "id=?", new String[]{"5"}Multi: "status=? OR score<?", new String[]{"inactive", "50"} |
| READ | db.query() |
Cursor(Result set pointer) |
Table: String Columns: String[] (null for *) Selection: String (Where) SelectArgs: String[] GroupBy/Having/Order: Strings |
Single: "name=?", new String[]{"Ali"}Multi: "gpa > ? AND year = ?", new String[]{"3.5", "2024"} |
| RAW SQL | db.execSQL() |
void |
SQL String: Full Query (Only for INSERT, UPDATE, DELETE, CREATE) |
execSQL("DELETE FROM users WHERE id=1") |
| RAW QUERY | db.rawQuery() |
Cursor |
SQL String: Full Query SelectArgs: String[] (For ? placeholders) |
rawQuery("SELECT * FROM users WHERE id=?", new String[]{"1"}) |
You notice I use COL_ID + " = ?" instead of COL_ID + " = " + id.
This is called Parameter Binding.
| SQLite Type | Description | Java Equivalent | Example Data |
|---|---|---|---|
INTEGER |
Whole numbers (positive or negative). | int, long, boolean* |
1, 404, 100293 |
REAL |
Numbers with decimals. | double, float |
3.14, 500.25, 0.05 |
TEXT |
Strings of text. | String |
"Ali", "Lahore", "0300-123" |
BLOB |
Binary Large Object. Raw data bytes. | byte[] |
Images, Audio files, PDF bytes |
NULL |
No value. | null |
(Empty cell) |
SQLite does not have dedicated types for Booleans or Dates. You must handle them using the 5 types above.
1. Boolean (True/False)
-
How to store: Use
INTEGER. -
0=false -
1=true -
Java Logic:
// Reading from DB
boolean isPass = cursor.getInt(index) == 1; 2. Date & Time
-
How to store: Use
TEXTorINTEGER. -
TEXT(Recommended):"2023-12-25 14:30:00"(ISO format). -
INTEGER:1672531200(Unix Timestamp - seconds since 1970). -
Java Logic: You save it as a String, and when you read it back, you use a
SimpleDateFormatto convert it to a Date object.
- Outer Class (
MyDatabaseHelper): No longer extendsSQLiteOpenHelper. It is now just a manager class. - Inner Class (
DbOpenHelper): Aprivate staticclass inside that extendsSQLiteOpenHelper. - Separate Pointers: We create
writeDbandreadDbvariables to hold the specific database instances. - Open/Close: We added
open()andclose()methods to manually manage the connection.
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import androidx.annotation.Nullable;
import java.util.ArrayList;
// Outer Class: Wraps the logic, does NOT extend SQLiteOpenHelper directly
public class MyDatabaseHelper {
// Database Info
private static final String DB_NAME = "MyCollege.db";
private static final int DB_VERSION = 1;
// Table Info
private static final String TABLE_NAME = "students";
private static final String COL_ID = "id";
private static final String COL_NAME = "name";
private static final String COL_GPA = "gpa";
// --- SEPARATE POINTERS ---
private final Context context;
private DbOpenHelper dbOpenHelper; // The Inner Helper
private SQLiteDatabase writeDb; // Pointer for writing (Insert/Update/Delete)
private SQLiteDatabase readDb; // Pointer for reading (Select)
// Constructor
public MyDatabaseHelper(Context context) {
this.context = context;
}
// MUST call this in Activity's onCreate()
public MyDatabaseHelper open() {
dbOpenHelper = new DbOpenHelper(context);
writeDb = dbOpenHelper.getWritableDatabase();
readDb = dbOpenHelper.getReadableDatabase();
return this;
}
// MUST call this in Activity's onDestroy()
public void close() {
if (dbOpenHelper != null) {
dbOpenHelper.close();
}
}
private static class DbOpenHelper extends SQLiteOpenHelper {
public DbOpenHelper(@Nullable Context context) {
super(context, DB_NAME, null, DB_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
String createTableQuery = "CREATE TABLE " + TABLE_NAME + " (" +
COL_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
COL_NAME + " TEXT, " +
COL_GPA + " REAL)";
db.execSQL(createTableQuery);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME);
onCreate(db);
}
}
// --- INSERT (Uses writeDb) ---
public boolean addStudent(String name, double gpa) {
ContentValues values = new ContentValues();
values.put(COL_NAME, name);
values.put(COL_GPA, gpa);
long result = writeDb.insert(TABLE_NAME, null, values);
return result != -1;
}
// --- UPDATE (Uses writeDb) ---
public boolean updateStudentGPA(int id, double newGpa) {
ContentValues values = new ContentValues();
values.put(COL_GPA, newGpa);
int rowsAffected = writeDb.update(TABLE_NAME, values, COL_ID + " = ?", new String[]{String.valueOf(id)});
return rowsAffected > 0;
}
// --- DELETE (Uses writeDb) ---
public boolean deleteStudent(int id) {
int rowsDeleted = writeDb.delete(TABLE_NAME, COL_ID + " = ?", new String[]{String.valueOf(id)});
return rowsDeleted > 0;
}
// --- GET ALL (Uses readDb) ---
public Cursor getAllStudents() {
return readDb.query(TABLE_NAME, null, null, null, null, null, COL_ID + " DESC");
}
// --- GET LIST (Uses readDb) ---
public ArrayList<Student> getStudentList() {
ArrayList<Student> studentList = new ArrayList<>();
Cursor cursor = getAllStudents();
if (cursor == null) return studentList;
int idIdx = cursor.getColumnIndex(COL_ID);
int nameIdx = cursor.getColumnIndex(COL_NAME);
int gpaIdx = cursor.getColumnIndex(COL_GPA);
for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
int id = cursor.getInt(idIdx);
String name = cursor.getString(nameIdx);
double gpa = cursor.getDouble(gpaIdx);
studentList.add(new Student(id, name, gpa));
}
cursor.close();
return studentList;
}
// --- SEARCH (Uses readDb) ---
public Cursor getStudentByName(String searchName) {
return readDb.query(TABLE_NAME, null, COL_NAME + " = ?", new String[]{searchName}, null, null, null);
}
}Key Change: You must call dbHelper.open() in onCreate and dbHelper.close() in onDestroy.
import android.database.Cursor;
import android.os.Bundle;
import android.util.Log;
import androidx.appcompat.app.AppCompatActivity;
import java.util.ArrayList;
public class MainActivity extends AppCompatActivity {
MyDatabaseHelper dbHelper;
private static final String TAG = "DB_TEST";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 1. Initialize Wrapper
dbHelper = new MyDatabaseHelper(this);
// 2. OPEN CONNECTION (MANDATORY NOW)
dbHelper.open();
Log.d(TAG, "--- Inserting Data ---");
dbHelper.addStudent("Ali", 3.2);
dbHelper.addStudent("Sara", 3.9);
dbHelper.addStudent("John", 2.5);
Log.d(TAG, "--- Updating Ali's GPA to 4.0 ---");
dbHelper.updateStudentGPA(1, 4.0);
Log.d(TAG, "--- Deleting John (ID 3) ---");
dbHelper.deleteStudent(3);
Log.d(TAG, "--- Reading All Students ---");
ArrayList<Student> list = dbHelper.getStudentList();
for (Student s : list) {
Log.d(TAG, "ID: " + s.id + ", Name: " + s.name + ", GPA: " + s.gpa);
}
Log.d(TAG, "--- Searching for 'Sara' ---");
Cursor cursor = dbHelper.getStudentByName("Sara");
if (cursor != null && cursor.moveToFirst()) {
// Using simple hardcoded column names here for testing
String name = cursor.getString(cursor.getColumnIndex("name"));
double gpa = cursor.getDouble(cursor.getColumnIndex("gpa"));
Log.d(TAG, "Found: " + name + " with GPA: " + gpa);
cursor.close();
}
}
@Override
protected void onDestroy() {
super.onDestroy();
// 3. CLOSE CONNECTION (Prevents memory leaks)
dbHelper.close();
}
}