Đâ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à xây dựng app PhoneBook. Ứng dụng có các thao tác như đọc, thêm, sửa , xóa các 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 bắt đầu thôi!
Nội dung chính của bài viết
- Xây dựng ứng dụng PhoneBook bằng cơ sở dữ liệu SQLite trong Android
- #1. Tạo một project mới
- #2. Tạo một Model Class
- #3. Tạo Form để Thêm/Sửa Contact
- #4. Khởi tạo SQLite database bằng cách dùng SQLiteOpenHelper class
- Companion Objects trong Kotlin
- #5. Triển khai ListView với Custom Adapter
- #6. Lấy dữ liệu từ database và đưa vào ListView
- Xử lý sự kiện click trong ListView
- #7. Cách thêm mới và chỉnh sửa danh bạ
Xây dựng ứng dụng PhoneBook bằng cơ sở dữ liệu SQLite trong Android
Để tránh lãng phí thời gian bằng lý thuyết khô khan, chúng ta bắt đầu 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.
#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 } }
#3. Tạo Form để Thêm/Sửa Contact
Tạo mới một activity và đặt tên nó là ContactManager.
Ở activity này, chúng ta sẽ thêm, sửa và xóa các dữ 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 hết sức đơn giản sử dụng TextView, EditText và 2 Buttons.
Phía dưới là đoạn code layout của nó.
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:padding="5dp" tools:context="com.androidpala.kotlindatabasetutorial.ContactManager"> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center" android:padding="10dp" android:text="Contact Details" android:textColor="@color/colorPrimary" android:textSize="20sp" android:textStyle="bold" /> <EditText android:id="@+id/fnametxt" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="First Name" android:inputType="textPersonName" android:text="" /> <EditText android:id="@+id/lnametxt" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="Last Name" android:inputType="textPersonName" android:text="" /> <EditText android:id="@+id/emailtxt" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="Email" android:inputType="textEmailAddress" android:text="" /> <EditText android:id="@+id/phone_txt" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="Phone Number" android:inputType="phone" android:text="" /> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center" android:orientation="horizontal"> <Button android:id="@+id/save_btn" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Add Contact" android:textSize="16sp" /> <Button android:id="@+id/delete_btn" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Delete Contact" android:textSize="16sp" /> </LinearLayout> </LinearLayout>
Và đây là diện mạo của layout. Cũng đơn giản phải không?
#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ó cho phép quản lý cơ sở dữ liệu, nâng cấp hoặc hạ cấp các 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.
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<ContactData> { var arraylist = ArrayList<ContactData>() 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ẽ giải thích qua về chức năng của các 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 xử lý database đã được sẵn sàng để được sửa dụng
#5. Triển khai ListView với Custom Adapter
Đây là 1 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:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context="com.androidpala.kotlindatabasetutorial.MainActivity"> <Button android:id="@+id/add_contact_btn" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center" android:padding="5dp" android:text="Add New Contact" android:textSize="18sp" android:textStyle="bold" /> <ListView android:id="@+id/contact_list" android:layout_width="match_parent" android:layout_height="match_parent" android:dividerHeight="1px"> </ListView> </LinearLayout>
Chúng ta cần phải tạo layout cho mỗi ô của ListView. Đây là 1 layout đơn giản chỉ gồm 1 ImageView và 1 TextView.
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal" android:gravity="center" android:padding="10dp"> <ImageView android:src="@mipmap/ic_face_black_48dp" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginRight="5dp"/> <TextView android:id="@+id/contact_name" android:layout_width="match_parent" android:layout_height="wrap_content" android:textSize="18sp" android:textStyle="bold"/> </LinearLayout>
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<ContactData>): BaseAdapter() { var arrayList = ArrayList<ContactData>() 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 dữ liệu từ database và đưa vào ListView
Tiếp theo, chúng ta sẽ sử dụng DatabaseHandler class để tương tác với database và hiển thị ra ListView thông qua Custom Adapter
class MainActivity : AppCompatActivity() { var ContactList = ArrayList<ContactData>() 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 ngữ Kotlin, việc triển khai lắng nghe sự kiện OnClick cực kì đơn giả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ó nhiệm vụ là thêm mới và chỉnh sửa các 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, 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, chúng ta sẽ thêm liên hệ mới. Ngược lại, nếu nó khác 0 thì 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 các hàm AddContact(), UpdateContact() and RemoveContact() của DatabaseHandler, đọc dữ liệu từ EditText và truyền nó vào form của ContentValue.
Cuối cùng, ứng dụng của chúng ta đã sẵn sàng để chạy trên máy ảo hoặc trên bất kì thiết bị android nào.
Sqlite android download toàn bộ 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 đó dễ dàng xây dựng được các ứng dụng cần tương tác với database, kết nối cơ sở dữ liệu SQlite trong Android.
Đừng quên like và chia sẻ bài viết nếu thấy có ích nhé
Cho mình hỏi là khi build các source của bạn. cứ báo lỗi phiên bản Kotlin khác nhau. các xử lý như thế nào. cụ thể như sau:
The Android Gradle plugin supports only Kotlin Gradle plugin version 1.2.51 and higher. Project ‘KotlinDatabaseTutorialCode’ is using version 1.2.21.
Hi
Nguyên nhân là do máy tính của bạn đang cài bản mới của Gradle nên nó chỉ support Kotlin plugin từ 1.2.51 trở lên. Cách đơn giản là bạn sửa lại file build.gradle trong source code để nâng version của kotlin plugin mà sử dụng cho project. đoạn sau: ext.kotlin_version = ‘1.2.21’ ==> ext.kotlin_version = ‘1.2.51’
Chúc bạn thành công