KOTLIN ANDROID APP DEVELOPMENT COURSE, Creating a Google Maps App

Today, I would like to cover how to create a ‘Google Maps app’, which is one of the practical examples in Android app development. In this tutorial, we will learn how to integrate Google Maps into an app using Kotlin and how to add various markers. Through this class, users will enhance their understanding of the basic Google Maps API and lay the groundwork necessary to implement more complex features based on it.

1. Setting Up the Development Environment

To use the Google Maps API, a few preparatory steps are required. Please follow the steps below.

1.1. Install Android Studio

Install the latest version of Android Studio. Additionally, a basic Android development environment should be set up.

1.2. Create a New Project

  • Open Android Studio and create a new project.
  • Select ‘Empty Activity’ as the project template.
  • Enter the project name and package, then click ‘Finish’ to create the project.

1.3. Create a Google Maps API Key

An API key is needed to use Google Maps. You can generate an API key through the following process.

  1. Visit the Google Cloud Console.
  2. Create a new project.
  3. In the navigation bar, go to ‘APIs & Services’ > ‘Library’.
  4. Find and enable ‘Maps SDK for Android’.
  5. Go to ‘Credentials’ and create a new API key.
  6. Copy the generated API key and store it in a safe place.

2. Gradle Configuration

Now, you need to modify the Gradle settings to add the Google Maps API to the project.

2.1. build.gradle (Project)

buildscript {
    ext.kotlin_version = '1.5.31'
    repositories {
        google()
        mavenCentral()
    }
    dependencies {
        classpath "com.android.tools.build:gradle:7.0.3"
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
    }
}

2.2. build.gradle (Module)

apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'

android {
    compileSdk 31

    defaultConfig {
        applicationId "com.example.mapapp"
        minSdk 21
        targetSdk 31
        versionCode 1
        versionName "1.0"

        // Add this line to set your API key
        manifestPlaceholders = [googleMapsKey: "YOUR_API_KEY_HERE"]
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
    implementation 'com.google.android.gms:play-services-maps:18.1.0'
    implementation 'androidx.appcompat:appcompat:1.3.1'
    implementation 'androidx.core:core-ktx:1.6.0'
}

3. Configuring AndroidManifest.xml

You need to add the necessary permissions and API key to the project’s manifest file.

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.mapapp">

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

    <application
        android:allowBackup="true"
        android:label="@string/app_name"
        android:icon="@mipmap/ic_launcher">
        <meta-data
            android:name="com.google.android.geo.API_KEY"
            android:value="${googleMapsKey}" />

        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

4. Setting Up the Layout File

We need to set up a basic layout that can display the map view.

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <fragment
        android:id="@+id/map"
        android:name="com.google.android.gms.maps.SupportMapFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    </fragment>

</LinearLayout>

5. Implementing Map Features

Now, let’s implement the basic map functionalities. The following code covers the basic map setup and adding markers.

package com.example.mapapp

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import com.google.android.gms.maps.CameraUpdateFactory
import com.google.android.gms.maps.GoogleMap
import com.google.android.gms.maps.OnMapReadyCallback
import com.google.android.gms.maps.SupportMapFragment
import com.google.android.gms.maps.model.LatLng
import com.google.android.gms.maps.model.MarkerOptions

class MainActivity : AppCompatActivity(), OnMapReadyCallback {

    private lateinit var mMap: GoogleMap

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

        val mapFragment = supportFragmentManager
            .findFragmentById(R.id.map) as SupportMapFragment
        mapFragment.getMapAsync(this)
    }

    override fun onMapReady(googleMap: GoogleMap) {
        mMap = googleMap

        // Add marker to the map
        val seoul = LatLng(37.5665, 126.978)
        mMap.addMarker(MarkerOptions().position(seoul).title("Seoul"))
        mMap.moveCamera(CameraUpdateFactory.newLatLng(seoul))
        
        // Set initial zoom
        mMap.moveCamera(CameraUpdateFactory.zoomTo(10f))
    }
}

6. Running the App

Now that all the configurations are complete, run the app. When you run the app on an Android device or emulator, you will see the Google Map displayed with a marker added in Seoul.

7. Conclusion

In this tutorial, we learned how to integrate Google Maps into an app using Kotlin. Based on this basic functionality, challenge yourself to add your own map features (e.g., location tracking, user location-based services, etc.). I hope to see you improve your skills through various Android app development tutorials in the future.

8. Additional Learning Resources

Thank you! If you have any questions, please leave them in the comments below.

kotlin android app development course, storing in shared preferences

Hello! Today, we will take a closer look at an important topic in Android app development: “Shared Preferences.” Shared Preferences is one of Android’s built-in methods for data storage that helps you save data as simple key-value pairs. It is primarily useful for storing user settings or simple data.

1. What are Shared Preferences?

Shared Preferences is an API used for storing small amounts of data within an Android application. It is suitable for storing basic data types such as strings, integers, and booleans. This data is retained even when the app is closed or restarted, allowing users to save and retrieve their settings information.

2. When to Use

Shared Preferences is useful in the following cases:

  • Storing user login information
  • User settings (theme, language, notification preferences, etc.)
  • Maintaining the app’s state (e.g., last viewed page)

3. Basic Setup for Using Shared Preferences

To use Shared Preferences, you first need to create an instance through the application context. Here’s a basic usage example:

3.1. Creating a SharedPreferences Instance

val sharedPreferences = getSharedPreferences("MyPreferences", Context.MODE_PRIVATE)

Here, “MyPreferences” is the name of the data you want to store.

4. Saving Data

Here is how to save data in Shared Preferences:

4.1. Saving a String

val editor = sharedPreferences.edit()
editor.putString("username", "JohnDoe")
editor.apply()

4.2. Saving an Integer

val editor = sharedPreferences.edit()
editor.putInt("userAge", 30)
editor.apply()

4.3. Saving a Boolean Value

val editor = sharedPreferences.edit()
editor.putBoolean("notificationsEnabled", true)
editor.apply()

5. Reading Data

Here’s how to read the saved data:

5.1. Reading a String

val username = sharedPreferences.getString("username", "defaultUser")

5.2. Reading an Integer

val userAge = sharedPreferences.getInt("userAge", 0)

5.3. Reading a Boolean Value

val notificationsEnabled = sharedPreferences.getBoolean("notificationsEnabled", false)

6. Deleting Data

If you want to delete specific data, you can do it as follows:

val editor = sharedPreferences.edit()
editor.remove("username")
editor.apply()

7. Deleting All Data

To delete all data, you can use the clear() method:

val editor = sharedPreferences.edit()
editor.clear()
editor.apply()

8. Example: Saving User Settings

Now, let’s go through a simple example of saving and loading user settings. First, create a new project in Android Studio. We will create a simple UI that takes the user’s name and age and saves it in Shared Preferences.

8.1. Layout File

Modify the res/layout/activity_main.xml file as follows:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="16dp">

    <EditText
        android:id="@+id/editTextUsername"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="Username"/>

    <EditText
        android:id="@+id/editTextAge"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="User Age"
        android:inputType="number"/>

    <Button
        android:id="@+id/buttonSave"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Save"/>

    <Button
        android:id="@+id/buttonLoad"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Load"/>

    <TextView
        android:id="@+id/textViewResult"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="16dp"/>

</LinearLayout>

8.2. MainActivity.kt File

Now, modify the MainActivity.kt file to save and load user input:

import android.content.Context
import android.os.Bundle
import android.widget.Button
import android.widget.EditText
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity

class MainActivity : AppCompatActivity() {
    private lateinit var sharedPreferences: SharedPreferences
    private lateinit var usernameEditText: EditText
    private lateinit var ageEditText: EditText
    private lateinit var saveButton: Button
    private lateinit var loadButton: Button
    private lateinit var resultTextView: TextView

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

        sharedPreferences = getSharedPreferences("MyPreferences", Context.MODE_PRIVATE)
        usernameEditText = findViewById(R.id.editTextUsername)
        ageEditText = findViewById(R.id.editTextAge)
        saveButton = findViewById(R.id.buttonSave)
        loadButton = findViewById(R.id.buttonLoad)
        resultTextView = findViewById(R.id.textViewResult)

        saveButton.setOnClickListener { saveData() }
        loadButton.setOnClickListener { loadData() }
    }

    private fun saveData() {
        val editor = sharedPreferences.edit()
        val username = usernameEditText.text.toString()
        val userAge = ageEditText.text.toString().toIntOrNull() ?: 0

        editor.putString("username", username)
        editor.putInt("userAge", userAge)
        editor.apply()

        resultTextView.text = "Saved: $username, Age: $userAge"
    }

    private fun loadData() {
        val username = sharedPreferences.getString("username", "defaultUser")
        val userAge = sharedPreferences.getInt("userAge", 0)

        resultTextView.text = "Loaded: $username, Age: $userAge"
    }
}

8.3. Running the App

Now run the app. After entering the username and age, clicking the ‘Save’ button will save the data to Preferences. Clicking the ‘Load’ button will display the saved data.

9. Tips and Precautions

  • Do not use Shared Preferences to store sensitive information such as passwords. For data where security is crucial, other data storage methods should be considered.
  • Shared Preferences is suitable for small amounts of data. If you need to store large amounts of data or complex data structures, it is recommended to use an SQLite database or Room library.
  • To reflect data changes immediately, you can use commit() instead of apply(), but this may block the UI thread and should be avoided.

10. Conclusion

In this tutorial, we learned how to use Shared Preferences in Android app development. We can easily save and load user settings through Preferences. By knowing various data storage methods and applying them in appropriate situations, broader app development becomes possible.

Now, try utilizing Shared Preferences to enhance user experience in your own apps. In the next tutorial, we will cover more advanced data storage methods. Thank you!

kotlin android app development course, arranged in a hierarchical structure – ConstraintLayout

When developing Android apps, the user interface (UI) plays a very important role, and various layouts can design the screen cleanly and effectively. Among them, ConstraintLayout is one of the powerful layouts that helps create complex UIs more easily. In this course, we will take a detailed look at how to use ConstraintLayout and the related techniques.

1. What is ConstraintLayout?

ConstraintLayout is one of the layouts used to place UI elements in Android. It allows each view to set its position based on its relationship with other views. In other words, the position of UI elements is determined by relative constraints. Using this layout, you can create smooth and responsive designs without complex hierarchies.

1.1 Why use ConstraintLayout?

  • Flexible Layout: It supports flexible UI design by defining relationships between various views.
  • Performance: Performance can be optimized by avoiding nested layouts.
  • Compatibility with Design Tools: It integrates easily with the Layout Editor provided by Android Studio.
  • Readability: The codebase is clean and intuitive.

2. Basic Structure of ConstraintLayout

When constructing a UI using ConstraintLayout, defining the constraints for each view is very important. The basic structure of ConstraintLayout is defined in XML, and we will learn the basic usage through the example below.

            
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello, ConstraintLayout!"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintLeft_toLeftOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>
            
        

In this example, you can see that the TextView is fixed to the top and left of the ConstraintLayout. This way, the position of each view can be varied.

3. Various Constraints of ConstraintLayout

In ConstraintLayout, you can adjust the position of views through various constraints. Here are the main constraints:

3.1 Relationship with Parent Elements

  • layout_constraintTop_toTopOf: Fixed to the top of the parent
  • layout_constraintBottom_toBottomOf: Fixed to the bottom of the parent
  • layout_constraintLeft_toLeftOf: Fixed to the left of the parent
  • layout_constraintRight_toRightOf: Fixed to the right of the parent

3.2 Relationship with Other Views

  • layout_constraintTop_toBottomOf: Fixed to the bottom of another view
  • layout_constraintBottom_toTopOf: Fixed to the top of another view
  • layout_constraintLeft_toRightOf: Fixed to the right of another view
  • layout_constraintRight_toLeftOf: Fixed to the left of another view

4. Practice: Creating a Simple App

Now, let’s create a simple app. This app will use TextView, EditText, and Button to display the text entered by the user on the screen.

4.1 Creating an XML Layout File

            
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <EditText
        android:id="@+id/editText"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        android:hint="Enter text here" />

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintTop_toBottomOf="@+id/editText"
        app:layout_constraintLeft_toLeftOf="parent"
        android:text="Submit" />

    <TextView
        android:id="@+id/textView"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        app:layout_constraintTop_toBottomOf="@+id/button"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        android:text="" />

</androidx.constraintlayout.widget.ConstraintLayout>
            
        

4.2 Writing Activity Code

Now we will write the MainActivity.kt file to display the input text in TextView when the button is clicked.

            
package com.example.constraintlayoutdemo

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.View
import android.widget.Button
import android.widget.EditText
import android.widget.TextView

class MainActivity : AppCompatActivity() {

    private lateinit var editText: EditText
    private lateinit var button: Button
    private lateinit var textView: TextView

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        
        editText = findViewById(R.id.editText)
        button = findViewById(R.id.button)
        textView = findViewById(R.id.textView)

        button.setOnClickListener {
            val inputText = editText.text.toString()
            textView.text = inputText
        }
    }
}
            
        

5. Summary

In this course, we explored the characteristics and usage of ConstraintLayout. ConstraintLayout is a powerful tool for efficiently placing complex UIs and allows flexible positioning of views through various constraints. Finally, we experienced the charm of ConstraintLayout through practical work by creating a simple app.

6. Additional Learning Resources

The ability to configure various UIs using a single layout is a very important aspect of ConstraintLayout in mobile app development. Here are more resources on ConstraintLayout.

Now, use ConstraintLayout in your app to create a better user experience! If you have any questions, feel free to ask in the comments. Thank you!

Kotlin Android App Development Course, Overlapping Layout – FrameLayout

1. Introduction

One of the various layouts used in Android app development, FrameLayout is
suitable for stacking views on top of each other.
This allows for the creation of complex UI effects by layering or overlaying views.
In this article, we will explore the basic concept and usage of FrameLayout,
and how to utilize this layout through actual Kotlin application examples.

2. Basic Concept of FrameLayout

FrameLayout is the simplest form of layout, aligning child views to the top-left corner,
and any additional child views are stacked on top of the previous views.
This advantage allows multiple views to be displayed in an overlapping manner, but
there are limitations in controlling the size and position of the views.
Therefore, FrameLayout is mainly used when applying simple UI components or overlays.

The advantage of FrameLayout is that it allows easy overlapping of views, while the disadvantage is
that its structure can be complex for managing multiple views efficiently.
Generally, FrameLayout is used when the overall layout is simple and suitable for such cases.

3. Using FrameLayout

FrameLayout can be easily declared in an XML layout file.
Below is an example of stacking multiple views using FrameLayout.

                

                    

                    

                
                ]]>
            

The code above illustrates stacking a TextView over an ImageView.
The ImageView fills the entire screen, while the TextView is positioned centrally.

Here, the android:layout_gravity="center" property sets
the text to be positioned in the center of the FrameLayout.

4. Example of Using FrameLayout with Kotlin

Now we will create a simple Android application using FrameLayout with Kotlin.
The example below includes a simple feature that changes the text upon a button click.

                
            

In the MainActivity class of this example, we defined the TextView and Button
and set it to change the text when the button is clicked.

Now let’s write the XML layout file.

                

                    

                    

                    

In the above XML layout file, the button and text are layered over the image.
The button is positioned at the bottom center of the screen using the layout_gravity property,
and the text is set to be centrally located.

5. Examples of Using FrameLayout

I will introduce several examples of using FrameLayout.
These examples clearly demonstrate how FrameLayout is utilized in actual application development.

5.1. Applying Overlay Effects

You can also use FrameLayout to apply overlay effects.
For example, let’s look at how to display additional information in overlay format over a photo in a gallery.

                

                    

                    

                        

                        
                    
                
                ]]>
            

The code above creates a UI where the title and description overlap a specific photo.
We use LinearLayout to arrange the text vertically and add a background color for the overlay effect.

5.2. Adding Dynamic Views

It is also possible to add views dynamically within FrameLayout.
For example, let’s add a TextView dynamically on button click.

                
            

The code above is an example where a new TextView is added to the FrameLayout at the center upon button click.

This way, FrameLayout allows flexible UI composition by adding or removing views dynamically.

6. Considerations When Using FrameLayout

When using FrameLayout, the following considerations should be taken into account.

  • Performance: Performance degradation may occur if many views overlap.
    Therefore, it should be avoided if not necessary.
  • Layout Complexity: As the complexity of the layout increases, readability may decrease,
    so it is recommended to use it for simple UIs.

7. Conclusion

FrameLayout is a powerful tool in Android UI design.
It can create simple overlapping views or modify the UI dynamically.
This article has covered the basic concepts and usage examples of FrameLayout,
and I hope you have understood various application methods.
Furthermore, I encourage you to utilize the powerful capabilities of FrameLayout in your Android application development.

course on Kotlin Android App Development, Creating an Improved To-Do List App

Hello! In this blog post, we will cover how to develop an Android app using Kotlin. Specifically, we will detail the process of creating an improved Todo List app. This app has been enhanced to be more useful by adding features such as a database and social sharing, in addition to the basic Todo List functionality.

Course Overview

This course consists of the following main topics:

  • Project Setup
  • UI Design
  • Setting up and implementing Room Database
  • Implementing add and delete functionality for tasks
  • Implementing functionality to mark tasks as completed
  • Adding social sharing functionality

1. Project Setup

We will create a new project through Android Studio. The project name will be set to ‘ImprovedTodoList’. At this time, please select Kotlin as the language and set the optimal API level.

1.1 Adding Gradle Dependencies

We need to add the Room database and other necessary libraries. Add the following code to the dependencies section of the ‘build.gradle (Module: app)’ file:

dependencies {
    implementation "androidx.room:room-runtime:2.4.2"
    kapt "androidx.room:room-compiler:2.4.2"
    implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.4.1"
    implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.4.1"
    implementation "androidx.activity:activity-ktx:1.4.0"
    implementation "androidx.appcompat:appcompat:1.4.1"
    implementation "com.google.android.material:material:1.5.0"
}

2. UI Design

First, we will design the basic UI. Design the UI in the activity_main.xml file with the following code:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <EditText
        android:id="@+id/editTextTodo"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="Enter your task"/>

    <Button
        android:id="@+id/buttonAdd"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Add"/>

    <RecyclerView
        android:id="@+id/recyclerView"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"/>

</LinearLayout>

2.1 Setting Up RecyclerView and Adapter

We will use RecyclerView to display the list of tasks. Create a file called todo_item.xml to define the layout of the items and add the following code:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal"
    android:padding="16dp">

    <CheckBox
        android:id="@+id/checkBox"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>

    <TextView
        android:id="@+id/textViewTodo"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:paddingStart="8dp"
        android:paddingEnd="8dp"/>

    <Button
        android:id="@+id/buttonDelete"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Delete"/>

</LinearLayout>

3. Setting up and Implementing Room Database

Now we will set up the Room database. Create an entity class called Todo to define the structure of the data table:

import androidx.room.Entity
import androidx.room.PrimaryKey

@Entity(tableName = "todo_table")
data class Todo(
    @PrimaryKey(autoGenerate = true) val id: Int = 0,
    val task: String,
    var isCompleted: Boolean = false
)

3.1 Creating TodoDao Interface

Create a DAO (Data Access Object) to interact with the Todo entity:

import androidx.room.Dao
import androidx.room.Insert
import androidx.room.Query
import androidx.room.Update

@Dao
interface TodoDao {
    @Insert
    suspend fun insert(todo: Todo)

    @Query("SELECT * FROM todo_table ORDER BY id ASC")
    suspend fun getAllTodos(): List

    @Update
    suspend fun update(todo: Todo)
}

3.2 Creating RoomDatabase Class

Create a class that defines the Room database:

import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
import android.content.Context

@Database(entities = [Todo::class], version = 1)
abstract class TodoDatabase : RoomDatabase() {
    abstract fun todoDao(): TodoDao

    companion object {
        @Volatile
        private var INSTANCE: TodoDatabase? = null

        fun getDatabase(context: Context): TodoDatabase {
            return INSTANCE ?: synchronized(this) {
                val instance = Room.databaseBuilder(
                    context.applicationContext,
                    TodoDatabase::class.java,
                    "todo_database"
                ).build()
                INSTANCE = instance
                instance
            }
        }
    }
}

4. Implementing Add and Delete Functionality for Tasks

We will connect the UI and Room database in MainActivity. We will implement the functionality to add tasks:

import android.os.Bundle
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.Observer
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import kotlinx.android.synthetic.main.activity_main.*

class MainActivity : AppCompatActivity() {
    private val todoViewModel: TodoViewModel by viewModels()

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

        val adapter = TodoAdapter()
        recyclerView.adapter = adapter
        recyclerView.layoutManager = LinearLayoutManager(this)

        todoViewModel.allTodos.observe(this, Observer { todos ->
            todos?.let { adapter.submitList(it) }
        })

        buttonAdd.setOnClickListener {
            val task = editTextTodo.text.toString()
            if (task.isNotEmpty()) {
                todoViewModel.insert(Todo(task = task))
                editTextTodo.text.clear()
            }
        }
    }
}

5. Implementing Functionality to Mark Tasks as Completed

We will add functionality to mark tasks as completed. We will add logic to reflect the state of the checkbox in the TodoAdapter:

import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.CheckBox
import android.widget.TextView
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView

class TodoAdapter : ListAdapter(TodoDiffCallback()) {
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TodoViewHolder {
        val view = LayoutInflater.from(parent.context).inflate(R.layout.todo_item, parent, false)
        return TodoViewHolder(view)
    }

    override fun onBindViewHolder(holder: TodoViewHolder, position: Int) {
        val todo = getItem(position)
        holder.bind(todo)
        holder.checkBox.setOnCheckedChangeListener { _, isChecked ->
            todo.isCompleted = isChecked
            // Update completion status
            // viewModel.update(todo) // Call update method in ViewModel
        }
    }

    class TodoViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        val textView: TextView = itemView.findViewById(R.id.textViewTodo)
        val checkBox: CheckBox = itemView.findViewById(R.id.checkBox)

        fun bind(todo: Todo) {
            textView.text = todo.task
            checkBox.isChecked = todo.isCompleted
        }
    }

    class TodoDiffCallback : DiffUtil.ItemCallback() {
        override fun areItemsTheSame(oldItem: Todo, newItem: Todo): Boolean {
            return oldItem.id == newItem.id
        }

        override fun areContentsTheSame(oldItem: Todo, newItem: Todo): Boolean {
            return oldItem == newItem
        }
    }
}

6. Adding Social Sharing Functionality

Finally, we will add functionality to share tasks on social media. We will implement the sharing functionality using Intent:

import android.content.Intent
import android.view.View
import androidx.recyclerview.widget.RecyclerView

class TodoAdapter : ListAdapter(TodoDiffCallback()) {
    // Previous code omitted...

    override fun onBindViewHolder(holder: TodoViewHolder, position: Int) {
        val todo = getItem(position)
        holder.bind(todo)

        holder.itemView.setOnClickListener {
            val shareIntent = Intent().apply {
                action = Intent.ACTION_SEND
                putExtra(Intent.EXTRA_TEXT, todo.task)
                type = "text/plain"
            }
            holder.itemView.context.startActivity(Intent.createChooser(shareIntent, "Choose where to share."))
        }
    }
}

Conclusion

Now the improved Todo List app is complete. This app provides functionality for users to add tasks, mark them as completed, delete tasks, and share them on social media. I hope this course helped you build an efficient app using Kotlin and the Room database. In the next post, we will cover additional features or other app development techniques. Thank you!