SQLite trong Android – Làm sao để sử dụng hiệu quả nhất – VNTALKING

Đây là một bài viết step-by-step hướng dẫn triển khai SQLite trong Android database với ngôn ngữ Kotlin. Trong bài viết này, mình sẽ code các chức năng cơ bản của một CSDL (CRUD). Chúng ta sẽ sử dụng SQLiteOpenHelper class để tạo và quản lý SQLite database.

Ví dụ minh họa trong suốt bài viết hướng dẫn là kiến thiết xây dựng app PhoneBook. Ứng dụng có những thao tác như đọc, thêm, sửa, xóa những danh bạ từ SQLite database Android .
Sau khi đọc xong bài viết này, bạn sẽ học được những sqlite android tutorial :

  • Làm thể nào để tạo là sử dụng SQLite database bằng Kotlin sử dụng SQLiteOpenHelper từ sqlite android example
  • Cách tạo một custom ListView bằng Custom Adapter.
  • Bắt sự kiện click vào từng contact trên ListView
  • Cách thêm mới, chỉnh sửa, và xóa danh bạ trong SQLite database
  • Cách chuyển dữ liệu từ activity này sang activity sử dụng Intent ( Tham khảo bài cũ Intent trong Android)

Ngôn ngữ được sử dụng trong bài viết này là Kotlin nhé

Chúng ta mở màn thôi !

SQLite trong Android - Làm sao để sử dụng hiệu quả nhất

Xây dựng ứng dụng PhoneBook bằng cơ sở tài liệu SQLite trong Android

Để tránh tiêu tốn lãng phí thời hạn bằng kim chỉ nan khô khan, tất cả chúng ta mở màn tạo mới project nhé

# 1. Tạo một project mới

Tạo mới một project trong Android Studio, sử dụng tùy chọn mặc định và đặt tên project là  KotlinDBTutorial. Đừng quên check vào checkbox với nội dung Include Kotlin support.

Mình sử dụng Empty Activity trong màn hình chọn activity để khởi tạo. Xong bước Sqlite android studio.

SQLite trong Android - Làm sao để sử dụng hiệu quả nhất

# 2. Tạo một Model Class

Tạo mới một Kotlin class và đặt tên nó là ContactData. Đây là một model class để database quản lý các bản ghi của bảng Contact như là 1 đối tượng trong Kotlin.

class ContactData {
 
    var conID:Int?=null
    var FirstName:String?=null
    var LastName:String?=null
    var Email:String?=null
    var PhoneNumber:String?=null
 
 
    constructor(id:Int,fname:String,lname:String,email:String,pnum:String){
 
        this.conID = id
        this.FirstName = fname
        this.LastName = lname
        this.Email = email
        this.PhoneNumber = pnum
 
    }
 
}

Tạo mới một activity và đặt tên nó là ContactManager.

Ở activity này, tất cả chúng ta sẽ thêm, sửa và xóa những tài liệu contacts từ database. Mình vừa mới tạo một form để thêm / sửa một contact. Đây là form rất là đơn thuần sử dụng TextView, EditText và 2 Buttons .
Phía dưới là đoạn code layout của nó .



 
    
 
    
 
    
 
    
 
    
 
    
 
 
        
 
        
 
    
 

Và đây là diện mạo của layout. Cũng đơn thuần phải không ?

SQLite trong Android - Làm sao để sử dụng hiệu quả nhất

# 4. Khởi tạo SQLite database bằng cách dùng SQLiteOpenHelper class

SQLiteOpenHelper được sử dụng để khởi tạo database. Nó được cho phép quản trị cơ sở tài liệu, tăng cấp hoặc hạ cấp những phiên bản của database .

Sqlite android create database đơn giản là tạo một class, đặt tên là DatabaseHandler. Chúng ta sẽ triển khai toàn bộ các chức năng CRUD của database trong class này.

Giải thích thêm: CRUD là gì? CRUD là viết tắt của Create, Read, Update và Delete. Đây là 4 thao tác cơ bản của mọi CSDL.

Dưới đây là đoạn code của DatabaseHandler class.

class DatabaseHandler : SQLiteOpenHelper {
 
 
    companion object {
 
        val Tag = "DatabaseHandler"
        val DBName = "ContactDB"
        val DBVersion = 1
 
        val tableName = "phoneTable"
        val ConID = "id"
        val FirstName = "fname"
        val LastName = "lname"
        val Number = "number"
        val Email = "email"
    }
 
    var context: Context? = null
    var sqlObj: SQLiteDatabase
 
    constructor(context: Context) : super(context, DBName, null, DBVersion) {
 
        this.context = context;
        sqlObj = this.writableDatabase;
    }
 
    override fun onCreate(p0: SQLiteDatabase?) {
 
        //SQL for creating table
        var sql1: String = "CREATE TABLE IF NOT EXISTS " + tableName + " " +
                "(" + ConID + " INTEGER PRIMARY KEY," +
                FirstName + " TEXT, " + LastName + " TEXT, " + Email +
                " TEXT," + Number + " TEXT );"
 
        p0!!.execSQL(sql1);
    }
 
    override fun onUpgrade(p0: SQLiteDatabase?, p1: Int, p2: Int) {
 
        p0!!.execSQL("Drop table IF EXISTS " + tableName)
        onCreate(p0)
 
    }
 
    fun AddContact(values: ContentValues): String {
 
        var Msg: String = "error";
        val ID = sqlObj!!.insert(tableName, "", values)
 
        if (ID > 0) {
            Msg = "ok"
        }
        return Msg
    }
 
    fun FetchContacts(keyword: String): ArrayList {
 
        var arraylist = ArrayList()
 
        val sqb = SQLiteQueryBuilder()
        sqb.tables = tableName
        val cols = arrayOf("id", "fname", "lname", "email", "number")
        val rowSelArg = arrayOf(keyword)
 
        val cur = sqb.query(sqlObj, cols, "fname like ?", rowSelArg, null, null, "fname")
 
        if (cur.moveToFirst()) {
 
            do {
                val id = cur.getInt(cur.getColumnIndex("id"))
                val fname = cur.getString(cur.getColumnIndex("fname"))
                val lname = cur.getString(cur.getColumnIndex("lname"))
                val email = cur.getString(cur.getColumnIndex("email"))
                val number = cur.getString(cur.getColumnIndex("number"))
 
                arraylist.add(ContactData(id, fname, lname, email, number))
 
            } while (cur.moveToNext())
        }
 
        var count: Int = arraylist.size
 
        return arraylist
    }
 
    fun UpdateContact(values: ContentValues, id: Int): String {
 
        var selectionArs = arrayOf(id.toString())
 
        val i = sqlObj!!.update(tableName, values, "id=?", selectionArs)
        if (i > 0) {
            return "ok";
        } else {
 
            return "error";
        }
    }
 
    fun RemoveContact(id: Int): String {
 
        var selectionArs = arrayOf(id.toString())
 
        val i = sqlObj!!.delete(tableName, "id=?", selectionArs)
        if (i > 0) {
            return "ok";
        } else {
 
            return "error";
        }
    }
}

Mình sẽ lý giải qua về tính năng của những hàm trên nhé

>>> Bạn có thể quan tâm: Kotlin Android Fragment Activity Dialog

Companion Objects trong Kotlin

Trước đây, khi sử dụng Java, mình hay sử dụng biến static để định nghĩa tên database, tên bảng, tên cột hay phiên bản database… Không có khái niệm biến/hàm static trong ngôn ngữ Kotlin. Thay vào đó, người ta sử dụng khái niệm “companion object”.

companion object {
 
        val Tag = "DatabaseHandler"
        val DBName = "ContactDB"
        val DBVersion = 1
 
        val tableName = "phoneTable"
        val ConID = "id"
        val FirstName = "fname"
        val LastName = "lname"
        val Number = "number"
        val Email = "email"
}

Trong hàm khởi tạo constructor(), chúng ta truyền vào tham số “context” từ activity đang hoạt động.

Database sẽ được tạo khi phương thức writableDatabase được gọi.

Hàm onCreate()được gọi khi database được khởi tạo. Chúng ta có thể tạo bảng của CSDL trong hàm này

Hàm onUpgrade()sử dụng khi chúng ta cần thay đổi cấu trúc của database hiện tại của ứng dụng như: thêm bảng, thêm cột…

  • Có thể bạn cần: Hướng dẫn upgrade database android một cách chuẩn nhất

Hàm AddContact()sẽ thêm 1 contact mới vào database.

Hàm FetchContacts()sẽ đọc toàn bộ records có trong bảng và trả về cho chúng ta 1 ArrayList.Nếu chúng ta truyền tham số là  “%” nó sẽ lấy toàn bộ records có trong database, ngược lại, nó sẽ tìm kiếm theo first_name.

UpdateContact() và RemoveContact()sẽ chỉnh sửa và xóa contact trong database. Chúng ta sẽ truyền contact_id vào hàm này với các contact_id là khóa chính của bảng contact.

Bây giờ, class giải quyết và xử lý database đã được chuẩn bị sẵn sàng để được sửa dụng

# 5. Triển khai ListView với Custom Adapter

Đây là 1 phong cách thiết kế cơ bản của ứng dụng sử dụng ListView và Button. Mở file layout của activity và thêm vào đoạn code như bên dưới :



 
    
 
    
 
    

Chúng ta cần phải tạo layout cho mỗi ô của ListView. Đây là 1 layout đơn thuần chỉ gồm 1 ImageView và 1 TextView .



 
    
 
    
 

Bây giờ, chúng ta có thể tạo 1 custom adapter cho ListView. Bạn hãy tạo mới 1 class và đặt tên nó là ContactAdapter và kế thừa BaseAdapter class.

Bên dưới là đoạn code hoàn chỉnh của ContactAdapter.kt

class ContactAdapter(con:Context, arrList:ArrayList): BaseAdapter() {
 
    var arrayList = ArrayList()
    var context: Context? = null
    var myInflater: LayoutInflater? = null
 
    init {
 
        this.context    = con
        this.myInflater = LayoutInflater.from(context)
        this.arrayList  = arrList
    }
 
    override fun getView(p0: Int, p1: View?, p2: ViewGroup?): View {
 
        var myView = myInflater!!.inflate(R.layout.list_block,null)
        var ConObj = arrayList[p0]
 
        var full_name : String = ConObj.FirstName.toString() +" "+ ConObj.LastName.toString()
        myView.contact_name.text = full_name
        return myView
    }
 
    override fun getItem(p0: Int): Any {
        return arrayList[p0]
    }
 
    override fun getItemId(p0: Int): Long {
        return p0.toLong()
    }
 
    override fun getCount(): Int {
        return arrayList.size
    }
}

# 6. Lấy tài liệu từ database và đưa vào ListView

Tiếp theo, tất cả chúng ta sẽ sử dụng DatabaseHandler class để tương tác với database và hiển thị ra ListView trải qua Custom Adapter

class MainActivity : AppCompatActivity() {
 
 
    var ContactList = ArrayList()   
 
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
 
    }
 
    override fun onResume() {
        super.onResume()
 
        var DB:DatabaseHandler = DatabaseHandler(this);
        ContactList = DB.FetchContacts("%");
 
        if(ContactList.size>0) {
 
            var ContactAdapterObj = ContactAdapter(this, ContactList)
            contact_list.adapter = ContactAdapterObj
 
              contact_list.onItemClickListener = AdapterView.OnItemClickListener { 
                                    adapterView, view, position, id ->
 
                //ContactList holds ContactData object  
                var fname = ContactList[position].FirstName;
                var lname = ContactList[position].LastName;
                var email = ContactList[position].Email;
                var phone = ContactList[position].PhoneNumber;
                var id = ContactList[position].conID
 
                 //Passing data to ContactManager activity.
                 var intent = Intent(this, ContactManager::class.java)
                 intent.putExtra("id", id)
                 intent.putExtra("fname", fname)
                 intent.putExtra("lname", lname)
                 intent.putExtra("email", email)
                 intent.putExtra("phone", phone)
                 intent.putExtra("action", "edit")
                 startActivity(intent)
 
               }
        }else{
 
          Toast.makeText(this, "No Contact Found", Toast.LENGTH_SHORT).show()
        }
 
        add_contact_btn.setOnClickListener(){
            var intent= Intent(this,ContactManager::class.java)
            startActivity(intent)
        }
 
    }
}

Trong hàm onResume(), chúng ta tạo ra 1 đối tượng của DatabaseHandler class và gọi tới  hàm FetchContact(). Kết quả trả về là ArrayList

Danh sách contacts sẽ được truyền qua ContactAdapter thông qua hàm khởi tạo.

var ContactAdapterObj = ContactAdapter(this, ContactList)
 contact_list.adapter = ContactAdapterObj

Xử lý sự kiện click trong ListView

Với ngôn từ Kotlin, việc tiến hành lắng nghe sự kiện OnClick cực kỳ đơn thuần và ngắn gọn hơn hơn Java rất nhiều

contact_list.onItemClickListener = AdapterView.OnItemClickListener { 
                                   adapterView, view, position, id ->
 
  }

Tương tự cho bắt sự kiện click với Button.
Chúng ta sẽ đi đến activity ContactManager khi button được nhấn. Activity ContactManager sẽ chứa 1 form để thêm và chỉnh sửa liên hệ.

add_contact_btn.setOnClickListener(){
            var intent= Intent(this,ContactManager::class.java)
            startActivity(intent)
        }

# 7. Cách thêm mới và chỉnh sửa danh bạ

Đây là activity thứ hai, có trách nhiệm là thêm mới và chỉnh sửa những contact .

class ContactManager : AppCompatActivity() {
 
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_contact_manager)
 
        // Getting id value pass by MainActivity via Intent
        // If no value pass, it will return 0
        var record_id = intent.getIntExtra("id", 0)
 
        if (record_id == 0) { //Add Record
 
            save_btn.text = "Add Contact"
 
        } else { //Update Record
 
            save_btn.text = "Update Contact"
            var _fname = intent.getStringExtra("fname")
            var _lname = intent.getStringExtra("lname")
            var _email = intent.getStringExtra("email")
            var _phone = intent.getStringExtra("phone")
 
            fnametxt.setText(_fname)
            lnametxt.setText(_lname)
            emailtxt.setText(_email)
            phone_txt.setText(_phone)
 
        }
 
        save_btn.setOnClickListener() {
 
            var a = fnametxt.text.toString();
            var b = lnametxt.text.toString();
            var c = emailtxt.text.toString();
            var d = phone_txt.text.toString();
 
            if(a==""){
 
                Toast.makeText(this, "Enter FirstName",
                        Toast.LENGTH_SHORT).show()
 
            }else if(d==""){
 
                Toast.makeText(this, "Enter Phone Number",
                        Toast.LENGTH_SHORT).show()
 
            }else{
 
                var values = ContentValues()
                values.put("fname", a)
                values.put("lname", b)
                values.put("email", c)
                values.put("number", d)
 
                 //Adding contact
                 if(record_id==0){
 
                    var DB: DatabaseHandler = DatabaseHandler(this);
 
                    var response = DB.AddContact(values);
                    if(response=="ok") {
 
                        Toast.makeText(this, "Contact Added",
                                Toast.LENGTH_SHORT).show()
 
                        var intent = Intent(this, MainActivity::class.java)
                        startActivity(intent)
                        finish()
 
                    }else{
                        Toast.makeText(this, "Not Added..Try again",
                                Toast.LENGTH_SHORT).show()
                    }
 
                }else{ //update contact
 
                    var DB: DatabaseHandler = DatabaseHandler(this);
 
                    var res: String = DB.UpdateContact(values, record_id)
 
                    if(res=="ok") {
                        Toast.makeText(this, "Contact Updated",
                                Toast.LENGTH_SHORT).show()
 
                        var intent = Intent(this, MainActivity::class.java)
                        startActivity(intent)
                        finish()
 
                    }else{
                        Toast.makeText(this, "Error..Try Again",
                                Toast.LENGTH_SHORT).show()
                    }
 
                }
 
            }
 
        }
 
        delete_btn.setOnClickListener() {
 
            var DB: DatabaseHandler = DatabaseHandler(this);
            var res: String = DB.RemoveContact(record_id)
 
            if(res=="ok") {
 
                Toast.makeText(this, "Contact Deleted",
                        Toast.LENGTH_SHORT).show()
            }else{
 
                Toast.makeText(this, "Error..Try Again",
                        Toast.LENGTH_SHORT).show()
            }
 
            var intent = Intent(this, MainActivity::class.java)
            startActivity(intent)
            finish()
 
        }
 
    }
}

Trong activity này, tất cả chúng ta sẽ thêm và chỉnh sửa contact tùy thuộc vào giá trị của trường _id. Nếu nó bằng 0, tất cả chúng ta sẽ thêm liên hệ mới. Ngược lại, nếu nó khác 0 thì tất cả chúng ta sẽ chỉnh sửa contact có id tương ứng với _id được nhập vào .
Chúng ta sử dụng những hàm AddContact ( ), UpdateContact ( ) and RemoveContact ( ) của DatabaseHandler, đọc tài liệu từ EditText và truyền nó vào form của ContentValue .
Cuối cùng, ứng dụng của tất cả chúng ta đã sẵn sàng chuẩn bị để chạy trên máy ảo hoặc trên bất kể thiết bị android nào .
Sqlite android tải về hàng loạt source code bên dưới nhé ! :

Ngoài ra, nếu đọc bài viết mà bạn vẫn có chỗ chưa hiểu thì có thể tham khảo video bên dưới để rõ thêm nhé

Hi vọng bài viết này sẽ giúp bạn hiểu và biết cách sử dụng SQLite trong Android. Qua đó thuận tiện thiết kế xây dựng được những ứng dụng cần tương tác với database, liên kết cơ sở tài liệu SQlite trong Android .
Đừng quên like và san sẻ bài viết nếu thấy có ích nhé