Type Converters in Room database

Abhishek Pathak
4 min readDec 9, 2022

Why we require converters in Room DB?

Let’s suppose you have to build an android app of currency exchange that contains the calculation or value display in actual value that is BigDecimal and also shows the approx. value or % change then you require a custom data type to store the value in single column.

What are converters do in Room DB?

In general, primitives data types are available in SQLite/Room but when you require some custom data types to store in single database column then we have to think something out of the box but interesting part of today’s learning in Room is, it provides a type converter which allows you to convert a custom data type to available/ primitive data type and vice versa.

Implementation of Room Type converter

Let’s have a realtime project that needs the room type converter.

Step 1 : We have @TypeConverter that will be apply over an method to create converter.

class Converter {
companion object {
@TypeConverter
@JvmStatic
fun fromBigDecimal(value: BigDecimal): String {
return value.toString()
}
@TypeConverter
@JvmStatic
fun toBigDecimal(value: String): BigDecimal {
return value.toBigDecimal()
}
}
}

Step 2: let’s create an entity of Room that is called Product

@Entity(tableName = "product_table")
data class Product(
@PrimaryKey var name: String,
var initialPrice: BigDecimal,
var price: BigDecimal
)

and have one price change data class to handle the change in price with initial value and change

data class PriceChange(
var name: String,
var initialPrice: BigDecimal,
var price: BigDecimal,
var change: BigDecimal
)

Step 3: Now time to create Product Dao to handle CRUD operations of Prodcut table.

@Dao
interface ProductDao {
@Query("SELECT * FROM product_table")
fun allProducts(): List<Product>
@Query("SELECT *, price-initialPrice as change FROM product_table")
fun priceChange(): List<PriceChange>
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insert(product: Product)
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insert(products: List<Product>)
}

Step 4: Now making an UI using table layout to display the price change and deal with all dao’s operation of product.

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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:padding="10dp"
tools:context=".MainActivity">

<TableLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="10dp"
android:paddingLeft="5dp"
android:paddingRight="5dp">
<TextView
android:id="@+id/txt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Price Conversions"
android:textSize = "20dp"
android:textStyle="bold">
</TextView>

<TableRow android:background="#51B435" android:padding="10dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Name" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Initial Price" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Price" />
</TableRow>
<TableRow android:background="#F0F7F7" android:padding="5dp">
<TextView
android:id="@+id/firstRow_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="1" />
<TextView
android:id="@+id/firstRow_initPrice"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="0.0" />
<TextView
android:id="@+id/firstRow_price"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="0.0" />
</TableRow>
<TableRow android:background="#F0F7F7" android:padding="5dp">
<TextView
android:id="@+id/secondRow_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="2" />
<TextView
android:id="@+id/secondRow_initPrice"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="0.0"/>
<TextView
android:id="@+id/secondRow_price"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="0.0" />
</TableRow>
<TableRow android:background="#F0F7F7" android:padding="5dp">
<TextView
android:id="@+id/thirdRow_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="3" />
<TextView
android:id="@+id/thirdRow_initPrice"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="0.0"/>
<TextView
android:id="@+id/thirdRow_price"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="0.0" />
</TableRow>
<TableRow android:background="#F0F7F7" android:padding="5dp">
<TextView
android:id="@+id/fourthRow_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="4" />
<TextView
android:id="@+id/fourthRow_initPrice"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="0.0"/>
<TextView
android:id="@+id/fourthRow_price"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="0.0" />
</TableRow>
</TableLayout>

<Button
android:id="@+id/btnAdd"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="20dp"
android:text="Add Product"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<Button
android:id="@+id/btnFetch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="20dp"
android:text="Fetch Product"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.8891929" />
</androidx.constraintlayout.widget.ConstraintLayout>

Step 5 : Finally set up the UI to implement and fetch the data.

class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
private lateinit var appDatabase: AppDatabase
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
init()
}
private fun init() {
appDatabase = AppDatabase.getInstance(this.applicationContext)!!
binding.apply {
btnAdd.setOnClickListener {
insertData()
}
btnFetch.setOnClickListener {
fetchData()
}
}
}
@SuppressLint("SetTextI18n")
private fun fetchData() {
val pPriceChanges = appDatabase.productDao().priceChange()
val first = pPriceChanges[0]
val second = pPriceChanges[1]
val third = pPriceChanges[2]
val fourth = pPriceChanges[3]
binding.apply {
firstRowName.text = first.name
firstRowInitPrice.text = first.initialPrice.toString()
firstRowPrice.text = first.price.toString()
secondRowName.text = second.name
secondRowInitPrice.text = second.initialPrice.toString()
secondRowPrice.text = second.price.toString()
thirdRowName.text = third.name
thirdRowInitPrice.text = third.initialPrice.toString()
thirdRowPrice.text = third.price.toString()
fourthRowName.text = fourth.name
fourthRowInitPrice.text = fourth.initialPrice.toString()
fourthRowPrice.text = fourth.price.toString()
}
}
private fun insertData() {
val list = mutableListOf<Product>().apply {
add(Product("Shoe", ("0.03245324234").toBigDecimal(), ("0.0922424").toBigDecimal()))
add(Product("Apple", ("0.03756536588").toBigDecimal(), ("0.0325524").toBigDecimal()))
add(Product("Cat", ("0.0556364847").toBigDecimal(), ("0.0588894").toBigDecimal()))
add(Product("Atari 2600", ("0.08636363605").toBigDecimal(), ("0.0835535").toBigDecimal()))
}
appDatabase.productDao().insertProducts(list)
}
}

Results

Database

Thanks for reading this article. Be sure to click 👏 below to applause this article if you found it helpful. It means a lot to me.

--

--