[Android] Database trong Android – P1 Tạo database

Chào các bạn, hôm nay mình bắt đầu hướng dẫn các bạn loạt bài về Database trong Android. Để có tính sinh động và cụ thể mình sẽ hướng dẫn các bạn làm ứng dụng “Ghi chú” một cách hoàn chỉnh có sử dụng database.

Toàn bộ code trong loạt bài này mình sẽ viết bằng tiếng Anh. Tuy nhiên thì tiếng anh này mình viết theo kiểu “dịch từ tiếng Việt” nên các bạn sẽ dễ dàng theo dõi.
IDE: Android studio 1.2.2
Android SDK 5.1.1
Min SDK: 4.0 (Android 4.0 trở lên sẽ dùng được ứng dụng)

Nếu trong java hoặc c# chúng ta đã quen dùng sql hoặc mysql để lưu trữ dữ liệu thì trong Android chúng ta dùng sqlite để lưu trữ.

Trong các loạt bài khác thường hướng dẫn các bạn dùng thằng lớp SQLiteDatabase để thao tác, nhưng mình sẽ hướng dẫn các bạn dùng kết hợp SQLiteOpenHelper để có thể thực hiện toàn diện nhất là trong quá trình nâng cấp ứng dụng chúng ta có thể cập nhật database một cách dễ dàng.

Bước 1: Tạo các class là đối tượng lưu trữ database

Ở bước này chúng ta tạo ra các class thường là các bảng trong database. Ví dụ bảng tb_note thì cần class Note.

package cachhoc.net.tut.demodatabase;

public class Note {
    private long id;
    private String title;
    private String content;
    
    public String getTitle() {
        return title;
    }

    public Note setTitle(String title) {
        this.title = title;
        return this;
    }

    public long getId() {
        return id;
    }

    public Note setId(long id) {
        this.id = id;
        return this;
    }

    public String getContent() {
        return content;
    }

    public Note setContent(String content) {
        this.content = content;
        return this;
    }
}

Trong code trên các bạn chú ý đến các phương thức set. Mình trả về toàn bộ là Note (chính là class nó luôn) điều này cho phép chúng ta thuận tiện trong việc set các giá trị và giảm thời gian chạy cho chương trình.

Bước 2: Khởi tạo database

Ở bước này chúng ta sẽ thực hiện tạo database. Bạn tạo một class DatabaseHelper kế thừa SQLiteOpenHelper như sau:

package cachhoc.net.tut.demodatabase;

import android.content.Context;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;

public class DatabaseHelper extends SQLiteOpenHelper {

    public static final String DATABASE_NAME = "note.db";

    /**
     * table note contain id, title, content
     */
    public static final String TABLE_NOTE = "tb_note";
    public static final String KEY_ID_NOTE = "id";
    public static final String KEY_TITLE_NOTE = "title";
    public static final String KEY_CONTENT_NOTE = "content";

    /**
     * string for create table note
     */
    public static final String CREATE_TABLE_NOTE =
            "CREATE TABLE " + TABLE_NOTE + "(" +
                    KEY_ID_NOTE + " INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL" +
                    ", " + KEY_TITLE_NOTE + " TEXT NOT NULL" +
                    "," + KEY_CONTENT_NOTE + " TEXT NOT NULL" +
                    ")";

    /**
     * value for update database
     */
    public static final int DATA_VERSION = 1;

    /**
     * Sqlite database
     */
    private SQLiteDatabase db;

    public DatabaseHelper(Context context) {
        super(context, DATABASE_NAME, null, DATA_VERSION);
    }

    /**
     * create db when app start, and only call when database don't create
     * When database created, it will not call
     */
    @Override
    public void onCreate(SQLiteDatabase db) {
        try {
            db.execSQL(CREATE_TABLE_NOTE);
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    /**
     * call when change DATA_VERSION
     * help we update database
     */
    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

    }

    /**
     * open database
     */
    public void open() {
        try {
            db = getWritableDatabase();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * close database
     */
    public void close() {
        if (db != null && db.isOpen()) {
            try {
                db.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

Ở đây các bạn có thể chú ý một số điểm sau:

  • Biến DATABASE_NAME: là tên database của chúng ta. Mỗi ứng dụng chỉ nên có duy nhất một database.

  • Bảng tb_note của chúng ta có các trường id, titlecontent và tương ứng chúng ta có chuỗi CREATE_TABLE_NOTE để tạo bảng

  • Biến DATA_VERSION chính là phiên bản database. Khi muốn thay đổi database ở các phiên bản sau chúng ta phải nâng phiên bản database lên để cập nhật.

  • Biến db là đối tượng lớp SQLiteDatabase sẽ là biến để thao tác các lệnh xử lý với database

  • Phương thức onCreate được viết đè từ lớp SQLiteOpenHelper sẽ giúp chúng ta tạo databse.

  • Phương thức onUpgrade sẽ giúp ta cập nhật database khi DATA_VERSION thay đổi.

  • Các phương thức open, close để đóng và mở database.

Bước 3: Viết các phương thức truy vấn database cơ bản

Ở bước này chúng ta sẽ viết một số phương thức cơ bản để lấy dữ liệu, chèn dữ liệu, cập nhật hoặc xóa.

/************************* method work with database *******************/

/**
 * get all row of table with sql command then return cursor
 * cursor move to frist to redy for get data
 */
public Cursor getAll(String sql) {
    open();
    Cursor cursor = db.rawQuery(sql, null);
    if (cursor != null) {
        cursor.moveToFirst();
    }
    close();
    return cursor;
}

/**
 * insert contentvaluse to table
 *
 * @param values value of data want insert
 * @return index row insert
 */
public long insert(String table, ContentValues values) {
    open();
    long index = db.insert(table, null, values);
    close();
    return index;
}

/**
 * update values to table
 *
 * @return index row update
 */
public boolean update(String table, ContentValues values, String where) {
    open();
    long index = db.update(table, values, where, null);
    close();
    return index > 0;
}

/**
 * delete id row of table
 */
public boolean delete(String table, String where) {
    open();
    long index = db.delete(table, where, null);
    close();
    return index > 0;
}
/************************* end of method work with database *******************/

Các bạn để ý sẽ thấy một số điểm mới so với sql và mysql

  • Trong phương thức getAll chúng ta trả về một Cursor, nó giống như một con trỏ để trỏ tới các bản ghi (row) trong bảng và ban đầu nó chưa trỏ đến đâu vì vậy chúng ta cần cho nó trỏ về row đầu tiên bằng lệnh cursor.moveToFirst();

  • Trong phương thức insert chúng ta gọi db.insert(table, null, values), trong đó values là một đối tượng thuộc lớp ContentValues chứa nội dung để chèn vào bảng. Chúng ta sẽ tìm hiểu cách dùng nó ở bước 3.

  • Các lệnh insert, update và delete đều trả về một số nguyên kiểu long là vị trí bản ghi được chèn, cập nhật hoặc xóa. Nếu không có bản ghi nào được thực hiện (lỗi) thì sẽ trả về là 0.

Bước 4: Viết các phương thức truy vấn cho các bảng

Sau khi thực hiện xong bước 2 coi như chúng ta đã hoàn thành việc tạo và truy xuất database và có thể bỏ qua bước này nếu muốn, tuy nhiên chúng ta sẽ gặp một số vấn đề khó hoặc xử lý dài dòng trong các class khác khi chúng ta gọi các phương thức để truy vấn. Vì vậy để thực hiện một cách dễ dàng hơn chúng ta nên tạo các phương thức truy vấn cho từng bảng cụ thể. Dưới đây là các phương thức truy xuất cho bảng tb_note.

/************************* method work with note table *******************/
/**
 * get Note by sql command
 *
 * @param sql sql to get note
 */
public Note getNote(String sql) {
    Note note = null;
    Cursor cursor = getAll(sql);
    if (cursor != null) {
        note = cursorToNote(cursor);
        cursor.close();
    }
    return note;
}

/**
 * @param sql get all notes with sql command
 * @return arraylist of note
 */
public ArrayList<Note> getListNote(String sql) {
    ArrayList<Note> list = new ArrayList<>();
    Cursor cursor = getAll(sql);

    while (!cursor.isAfterLast()) {
        list.add(cursorToNote(cursor));
        cursor.moveToNext();
    }
    cursor.close();

    return list;
}

/**
 * insert note to table
 *
 * @param note note to insert
 * @return id of note
 */
public long insertNote(Note note) {
    return insert(TABLE_NOTE, noteToValues(note));
}

/**
 * @param note note to update
 * @return id of note update
 */
public boolean updateNote(Note note) {
    return update(TABLE_NOTE, noteToValues(note), KEY_ID_NOTE + " = " + note.getId());
}

/**
 * delete id row of table
 */
public boolean deleteNote(String where) {
    return delete(TABLE_NOTE, where);
}

/**
 * convert note to contentvalues
 * don't put id of note because
 * when insert id will auto create
 * when update we don't update id
 */
private ContentValues noteToValues(Note note) {
    ContentValues values = new ContentValues();
    values.put(KEY_TITLE_NOTE, note.getTitle());
    values.put(KEY_CONTENT_NOTE, note.getContent());
    return values;
}

/**
 * convert cursor to note
 */
private Note cursorToNote(Cursor cursor) {
    Note note = new Note();
    note.setId(cursor.getInt(cursor.getColumnIndex(KEY_ID_NOTE)))
            .setTitle(cursor.getString(cursor.getColumnIndex(KEY_TITLE_NOTE)))
            .setContent(cursor.getString(cursor.getColumnIndex(KEY_CONTENT_NOTE)));
    return note;
}
/************************* end of method work note table *******************/

Trong đoạn code trên mình đã comment khá rõ ràng, các bạn cố gắng tìm hiểu.

Full code

package cachhoc.net.tut.demodatabase;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;

import java.util.ArrayList;

public class DatabaseHelper extends SQLiteOpenHelper {

    public static final String DATABASE_NAME = "note.db";

    /**
     * table note contain id, title, content
     */
    public static final String TABLE_NOTE = "tb_note";
    public static final String KEY_ID_NOTE = "id";
    public static final String KEY_TITLE_NOTE = "title";
    public static final String KEY_CONTENT_NOTE = "content";

    /**
     * string for create table note
     */
    public static final String CREATE_TABLE_NOTE =
            "CREATE TABLE " + TABLE_NOTE + "(" +
                    KEY_ID_NOTE + " INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL" +
                    ", " + KEY_TITLE_NOTE + " TEXT NOT NULL" +
                    "," + KEY_CONTENT_NOTE + " TEXT NOT NULL" +
                    ")";

    /**
     * value for update database
     */
    public static final int DATA_VERSION = 1;

    /**
     * Sqlite database
     */
    private SQLiteDatabase db;

    public DatabaseHelper(Context context) {
        super(context, DATABASE_NAME, null, DATA_VERSION);
    }

    /**
     * create db when app start, and only call when database don't create
     * When database created, it will not call
     */
    @Override
    public void onCreate(SQLiteDatabase db) {
        try {
            db.execSQL(CREATE_TABLE_NOTE);
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    /**
     * call when change DATA_VERSION
     * help we update database
     */
    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

    }

    /**
     * open database
     */
    public void open() {
        try {
            db = getWritableDatabase();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * close database
     */
    public void close() {
        if (db != null && db.isOpen()) {
            try {
                db.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }

    /************************* method work with database *******************/

    /**
     * get all row of table with sql command then return cursor
     * cursor move to frist to redy for get data
     */
    public Cursor getAll(String sql) {
        open();
        Cursor cursor = db.rawQuery(sql, null);
        if (cursor != null) {
            cursor.moveToFirst();
        }
        close();
        return cursor;
    }

    /**
     * insert contentvaluse to table
     *
     * @param values value of data want insert
     * @return index row insert
     */
    public long insert(String table, ContentValues values) {
        open();
        long index = db.insert(table, null, values);
        close();
        return index;
    }

    /**
     * update values to table
     *
     * @return index row update
     */
    public boolean update(String table, ContentValues values, String where) {
        open();
        long index = db.update(table, values, where, null);
        close();
        return index > 0;
    }

    /**
     * delete id row of table
     */
    public boolean delete(String table, String where) {
        open();
        long index = db.delete(table, where, null);
        close();
        return index > 0;
    }


    /************************* end of method work with database *******************/
    
    /************************* method work with note table *******************/
    /**
     * get Note by sql command
     *
     * @param sql sql to get note
     */
    public Note getNote(String sql) {
        Note note = null;
        Cursor cursor = getAll(sql);
        if (cursor != null) {
            note = cursorToNote(cursor);
            cursor.close();
        }
        return note;
    }

    /**
     * @param sql get all notes with sql command
     * @return arraylist of note
     */
    public ArrayList<Note> getListNote(String sql) {
        ArrayList<Note> list = new ArrayList<>();
        Cursor cursor = getAll(sql);

        while (!cursor.isAfterLast()) {
            list.add(cursorToNote(cursor));
            cursor.moveToNext();
        }
        cursor.close();

        return list;
    }

    /**
     * insert note to table
     *
     * @param note note to insert
     * @return id of note
     */
    public long insertNote(Note note) {
        return insert(TABLE_NOTE, noteToValues(note));
    }

    /**
     * @param note note to update
     * @return id of note update
     */
    public boolean updateNote(Note note) {
        return update(TABLE_NOTE, noteToValues(note), KEY_ID_NOTE + " = " + note.getId());
    }

    /**
     * delete id row of table
     */
    public boolean deleteNote(String where) {
        return delete(TABLE_NOTE, where);
    }

    /**
     * convert note to contentvalues
     * don't put id of note because
     * when insert id will auto create
     * when update we don't update id
     */
    private ContentValues noteToValues(Note note) {
        ContentValues values = new ContentValues();
        values.put(KEY_TITLE_NOTE, note.getTitle());
        values.put(KEY_CONTENT_NOTE, note.getContent());
        return values;
    }

    /**
     * convert cursor to note
     */
    private Note cursorToNote(Cursor cursor) {
        Note note = new Note();
        note.setId(cursor.getInt(cursor.getColumnIndex(KEY_ID_NOTE)))
                .setTitle(cursor.getString(cursor.getColumnIndex(KEY_TITLE_NOTE)))
                .setContent(cursor.getString(cursor.getColumnIndex(KEY_CONTENT_NOTE)));
        return note;
    }
    /************************* end of method work note table *******************/
}

Trong phần 2 mình sẽ hướng dẫn các bạn tạo giao diện theo phong cách Material Design và băt sự kiện tạo app hoàn chỉnh.

Bài viết được thực hiện trong loạt bài hướng dẫn Database trong Android bởi nguyenvanquan7826


Loạt bài hướng dẫn Android

[rps-include post=”4210″ shortcodes=”false”]