top of page

Integrating SQLite in Android App using Kotlin: A Step-by-Step Guide

This blog will provide a step-by-step guide on integrating SQLite in an Android app using the Kotlin programming language. SQLite is a popular choice for local data storage in Android development due to its lightweight and efficient nature. By following the steps outlined in this blog, you will be able to easily integrate SQLite into your Android app and leverage its benefits for data storage.




The goal of this blog is to provide a comprehensive guide on integrating SQLite in an Android app using Kotlin. By the end of this tutorial, you will have a clear understanding of the following:


  1. How to add the SQLite dependency to your Android project.

  2. How to create a SQLite database and table in your Android app.

  3. How to perform CRUD (Create, Read, Update, Delete) operations on the SQLite database.

  4. How to display the SQLite data in a RecyclerView.


This tutorial aims to provide a practical and hands-on approach to integrating SQLite in an Android app, with code examples and explanations to help you understand the concepts better. By the end of this tutorial, you should be able to integrate SQLite in your own Android app and leverage its benefits for local data storage.


Advantages of using SQLite in Android apps:

  1. Lightweight: SQLite is a lightweight database management system that requires minimal setup and maintenance, making it an ideal choice for mobile apps.

  2. Efficient: SQLite is designed for efficiency and can handle a large amount of data without sacrificing performance.

  3. Easy to integrate: SQLite is easy to integrate into Android apps, as it is part of the Android SDK.

  4. Portable: SQLite databases can be easily moved between different devices, making it an ideal choice for cross-platform apps.

Disadvantages of using SQLite in Android apps:

  1. Limited scalability: SQLite is not designed for large-scale databases, and its performance may suffer if the database grows too large.

  2. Limited functionality: SQLite does not support advanced database features such as stored procedures and triggers.

  3. No centralized database: SQLite databases are local to the device and cannot be shared across different devices without implementing custom syncing solutions.

  4. No built-in security: SQLite does not provide built-in security features, and developers must implement their own security measures to protect sensitive data.

Implementation of the Sqlite database in Android



SQLite is a lightweight, open-source relational database management system that is used to store data in an organized manner. In Android, SQLite is a commonly used database to store and retrieve data. In this blog, we will discuss how to integrate SQLite in an Android app using Kotlin.


Step 1 : Adding Dependencies

To start with, we need to create a new Android Studio project and add the required dependencies to our project. We can add the following dependencies to our project's build.gradle file:


dependencies {
    implementation 'androidx.appcompat:appcompat:1.4.1'
    implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
    implementation 'androidx.recyclerview:recyclerview:1.2.1'
    implementation 'androidx.sqlite:sqlite:2.1.0'
}

Once the dependencies are added, we need to create a database helper class that will help us to interact with the SQLite database.


Step 2: Create DatabaseHelper class



class DatabaseHelper(context: Context) : SQLiteOpenHelper(context, DATABASE_NAME, null, DATABASE_VERSION) {

    companion object {
        private const val DATABASE_NAME = "employee.db"
        private const val DATABASE_VERSION = 1

        private const val CREATE_TABLE_EMPLOYEE = """
            CREATE TABLE employee (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                employee_name TEXT,
                employee_code TEXT,
                employee_image BLOB
            )
        """
    }

    override fun onCreate(db: SQLiteDatabase) {
        // create the employee table
        db.execSQL(CREATE_TABLE_EMPLOYEE)
    }

    override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
        // drop the employee table if it exists
        db.execSQL("DROP TABLE IF EXISTS employee")

        // create the new employee table
        onCreate(db)
    }
}

we have added the "employee_name", "employee_code", and "employee_image" columns to the CREATE_TABLE_EMPLOYEE SQL statement in the onCreate() function. We have also updated the onUpgrade() function to drop and recreate the "employee" table if the database version has changed.


This updated DatabaseHelper class can be used in conjunction with the updated EmployeeDatabase class to handle the CRUD operations for the "employee" table in SQLite.


Step 3: Create an Employee Database

CRUD operations for a table named "employee" with columns "employee_name", "employee_code", and "employee_image":



class EmployeeDatabase(context: Context) {

    private val databaseHelper = DatabaseHelper(context)

    fun insert(name: String, code: String, image: ByteArray) {
        // get the writable databaseval db = databaseHelper.writableDatabase

        // create the ContentValues objectval values = ContentValues().apply {
            put("employee_name", name)
            put("employee_code", code)
            put("employee_image", image)
        }

        // insert the data into the table
        db.insert("employee", null, values)

        // close the database connection
        db.close()
    }

    fun getAll(): List<Employee> {
        val list = mutableListOf<Employee>()

        // get the readable databaseval db = databaseHelper.readableDatabase

        // select all data from the tableval cursor = db.rawQuery("SELECT * FROM employee", null)

        // iterate through the cursor and add the data to the listwhile (cursor.moveToNext()) {
            val name = cursor.getString(cursor.getColumnIndex("employee_name"))
            val code = cursor.getString(cursor.getColumnIndex("employee_code"))
            val image = cursor.getBlob(cursor.getColumnIndex("employee_image"))
            list.add(Employee(name, code, image))
        }

        // close the cursor and database connection
        cursor.close()
        db.close()

        return list
    }

    fun update(id: Int, name: String, code: String, image: ByteArray) {
        // get the writable databaseval db = databaseHelper.writableDatabase

        // create the ContentValues objectval values = ContentValues().apply {
            put("employee_name", name)
            put("employee_code", code)
            put("employee_image", image)
        }

        // update the data in the table
        db.update("employee", values, "id = ?", arrayOf(id.toString()))

        // close the database connection
        db.close()
    }

    fun delete(id: Int) {
        // get the writable databaseval db = databaseHelper.writableDatabase

        // delete the data from the table
        db.delete("employee", "id = ?", arrayOf(id.toString()))

        // close the database connection
        db.close()
    }

    data class Employee(val name: String, val code: String, val image: ByteArray)
}

In this updated code, we have added three parameters to the insert(), update(), and getAll() functions to handle the "employee_name", "employee_code", and "employee_image" columns of the "employee" table. We have also defined a data class Employee to represent the data of an employee in the table.


Note that the image column is of type BLOB in SQLite, so we have used the getBlob() function to retrieve the image data from the cursor. When inserting an image, we can pass the image data as a ByteArray.

Step 4: Create an Adapter and viewHolder Class

adapter and view holder class that can be used to display the "employee" data in a RecyclerView:


class EmployeeAdapter(private val employeeList: List<EmployeeDatabase.Employee>) : RecyclerView.Adapter<EmployeeAdapter.EmployeeViewHolder>() {

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): EmployeeViewHolder {
        val view = LayoutInflater.from(parent.context).inflate(R.layout.item_employee, parent, false)
        return EmployeeViewHolder(view)
    }

    override fun onBindViewHolder(holder: EmployeeViewHolder, position: Int) {
        val employee = employeeList[position]
        holder.bind(employee)
    }

    override fun getItemCount(): Int = employeeList.size

    class EmployeeViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {

        fun bind(employee: EmployeeDatabase.Employee) {
            itemView.findViewById<TextView>(R.id.tv_employee_name).text = employee.name
            itemView.findViewById<TextView>(R.id.tv_employee_code).text = employee.code
            itemView.findViewById<ImageView>(R.id.iv_employee_image).setImageBitmap(BitmapFactory.decodeByteArray(employee.image, 0, employee.image.size))
        }
    }
}

In this example, we have created an EmployeeAdapter class that extends the RecyclerView.Adapter class and takes a list of EmployeeDatabase.Employee objects as a constructor parameter. The adapter inflates the layout for each item in the onCreateViewHolder() function, binds the data to the views in the onBindViewHolder() function, and returns the size of the list in the getItemCount() function.


We have also created an EmployeeViewHolder class that extends the RecyclerView.ViewHolder class and takes a View object as a constructor parameter. The view holder binds the EmployeeDatabase.Employee data to the views in the bind() function.


Note that in the bind() function, we have decoded the image data from the ByteArray using the BitmapFactory.decodeByteArray() function and set the image bitmap to the ImageView.


With these adapter and view holder classes, we can display the "employee" data in a RecyclerView in an Android application.


Step 5: Create XML file for the main activity and card item

XML code for the MainActivity and item_employee layout files:

activity_main.xml:


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"><androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_employee_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp"
android:clipToPadding="false"
android:background="@android:color/white" />
</LinearLayout>

In this example, we have a LinearLayout as the root view with a RecyclerView inside it. The RecyclerView has an ID of rv_employee_list and fills the entire screen. We have added padding to the RecyclerView and set clipToPadding to false to prevent the padding from being clipped. We have also set the background color of the RecyclerView to white.


item_employee.xml:


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="16dp"
android:gravity="center_vertical">
<ImageView
android:id="@+id/iv_employee_image"
android:layout_width="64dp"
android:layout_height="64dp"
android:scaleType="centerCrop"
android:src="@drawable/ic_person" />
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical"
android:layout_marginStart="16dp">
<TextView
android:id="@+id/tv_employee_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="18sp"
android:textStyle="bold"
android:textColor="@android:color/black" />
<TextView
android:id="@+id/tv_employee_code"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="14sp"
android:textColor="@android:color/darker_gray" 
/>
</LinearLayout>
</LinearLayout>

In this example, we have a LinearLayout as the root view with an ImageView and another LinearLayout inside it.


The ImageView has an ID of iv_employee_image and is set to a default "person" icon using the src attribute. The second LinearLayout has a weight of 1 to fill the remaining horizontal space and contains two TextView views. The first TextView has an ID of tv_employee_name, is set to bold, and uses a font size of 18sp. The second TextView has an ID of tv_employee_code and uses a font size of 14sp.

Step 6: Create Main Activity class

MainActivity class that adds data to the database and displays it in a RecyclerView:


class MainActivity : AppCompatActivity() {

    private lateinit var employeeRecyclerView: RecyclerView
    private lateinit var employeeAdapter: EmployeeAdapter

    private lateinit var database: EmployeeDatabase

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        employeeRecyclerView = findViewById(R.id.rv_employee_list)

        employeeAdapter = EmployeeAdapter(emptyList())
        employeeRecyclerView.adapter = employeeAdapter

        database = EmployeeDatabase(this)

        // Add sample data to the database
        database.addEmployee(EmployeeDatabase.Employee("John Smith", "JNS001", getByteArrayFromDrawable(R.drawable.employee1)))
        database.addEmployee(EmployeeDatabase.Employee("Jane Doe", "JDO002", getByteArrayFromDrawable(R.drawable.employee2)))
        database.addEmployee(EmployeeDatabase.Employee("Bob Johnson", "BJH003", getByteArrayFromDrawable(R.drawable.employee3)))

        // Get all employees from the database and display them in the RecyclerViewval employeeList = database.getAllEmployees()
        employeeAdapter = EmployeeAdapter(employeeList)
        employeeRecyclerView.adapter = employeeAdapter
    }

    // Helper function to convert a drawable resource to a byte arrayprivate fun getByteArrayFromDrawable(drawableId: Int): ByteArray {
        val drawable = ContextCompat.getDrawable(this, drawableId) ?: throw IllegalArgumentException("Drawable not found")
        val bitmap = (drawable as BitmapDrawable).bitmap
        val stream = ByteArrayOutputStream()
        bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream)
        return stream.toByteArray()
    }
}

In this example, we have created a MainActivity class that extends the AppCompatActivity class. We have declared the employeeRecyclerView and employeeAdapter variables as class properties and initialized them in the onCreate() function. We have also declared a database variable of type EmployeeDatabase and initialized it in the onCreate() function.


In the onCreate() function, we have added sample data to the database using the database.addEmployee() function. We have then retrieved all the employees from the database using the database.getAllEmployees() function and set them to the adapter using the employeeAdapter variable.


We have also created a helper function called getByteArrayFromDrawable() that takes a drawable resource ID as a parameter, converts it to a bitmap, compresses it to a PNG byte array, and returns the byte array.


Note that in the EmployeeDatabase class and EmployeeAdapter class examples, we have added an image column to the employee table to store the employee image as a byte array. In the MainActivity class, we have used the getByteArrayFromDrawable() function to convert the drawable resources to byte arrays and passed them to the database.addEmployee() function when adding the sample data to the database. In the EmployeeAdapter class, we have used the BitmapFactory.decodeByteArray() function to decode the byte array to a bitmap and set it to the ImageView in the bind() function.



Conclusion:

SQLite is a powerful and lightweight database that can be integrated into Android apps to store data locally. Kotlin provides a modern and concise programming language for Android app development. By combining SQLite and Kotlin, we can create efficient and easy-to-maintain apps that handle data storage and retrieval with ease.


In this blog post, we have explored an example of integrating SQLite with Kotlin in an Android app. We have covered the steps required to create a database, insert data into it, and display the data in a RecyclerView. We have also shown how to use the ByteArray data type to store images in the database

.

By following the examples in this blog post, you should be able to integrate SQLite with Kotlin in your own Android apps and efficiently store and retrieve data as needed.






If you need help with your SQLite and Kotlin integration project, or any other project or assignment related to programming, don't hesitate to reach out to CodersArts. Our team of experienced developers and tutors can help you with any programming problem or task you may have, and provide you with personalized assistance to ensure your success. Contact us today to learn more about our services and get started on your project.



Thank you




The journey of solving bugs and completing projects on time in Kotlin can be challenging and lonely. If you need help regarding other sides of Kotlin, we’re here for you!






Drop an email to us at contact@codersarts.com with the Project title, deadline, and requirement files. Our email team will revert back promptly to get started on the work.




bottom of page