Home > Software design >  How to convert String into an Int, in order to used as uid of RoomDatabase
How to convert String into an Int, in order to used as uid of RoomDatabase

Time:10-15

I was deveopong a Kotlin App where I try to implement Room and I conection with an API with retrun diferents cats Images, which I load into the App.

My problems comes in order I have 2 Models of data: One for the API conection and another for the RoomDatabase.

RoomUnsplashPhoto.kt

package com.example.mvvm_retrofit_imagesearchapp.data

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

//Entity que almaceno en Room a partir
// de la imagen mostrada en el DetailFragment
@Entity
data class RoomUnsplashPhoto(
    @PrimaryKey(autoGenerate = true) val uid: Int,
    @ColumnInfo(name = "description") val description: String?,
    @ColumnInfo(name = "url") val url: String?,
    @ColumnInfo(name="user") val user:String?,
)

And the model of the API

UnsplashPhoto.kt

package com.example.mvvm_retrofit_imagesearchapp.data

import android.os.Parcelable
import kotlinx.android.parcel.Parcelize

@Parcelize
data class UnsplashPhoto(
    val id: String?,
    val description: String?,
    val urls: UnsplashPhotoUrls,
    val user: UnsplashUser
) : Parcelable {

    @Parcelize
    data class UnsplashPhotoUrls(
        val raw: String,
        val full: String,
        val regular: String,
        val small: String,
        val thumb: String,
    ) : Parcelable

    @Parcelize
    data class UnsplashUser(
        val name: String,
        val username: String
    ) : Parcelable {
        val attributionUrl get() =
            "https://unsplash.com/$username?utm_source=ImageSearchApp&utm_medium=referral"
    }
}

So as you can see the problem comes when I try to convert the id of the API which is an String, into an uid of my Room Model, which need to be a Int or Long, I guess

The error is the follow:

java.lang.NumberFormatException: For input string: "pdALzg0yN-8"

Finally the Fragment where I try to implement this is this:

package com.example.mvvm_retrofit_imagesearchapp.ui.detail

import android.content.Intent
import android.graphics.drawable.Drawable
import android.net.Uri
import android.os.Bundle
import android.util.Log
import android.view.View
import android.widget.Toast
import androidx.core.view.isVisible
import androidx.fragment.app.Fragment
import androidx.navigation.fragment.navArgs
import androidx.room.Room
import com.bumptech.glide.Glide
import com.bumptech.glide.load.DataSource
import com.bumptech.glide.load.engine.GlideException
import com.bumptech.glide.request.RequestListener
import com.bumptech.glide.request.RequestOptions
import com.bumptech.glide.request.target.Target
import com.example.mvvm_retrofit_imagesearchapp.R
import com.example.mvvm_retrofit_imagesearchapp.data.RoomUnsplashPhoto
import com.example.mvvm_retrofit_imagesearchapp.data.UnsplashPhoto
import com.example.mvvm_retrofit_imagesearchapp.databinding.FragmentDetailBinding
import com.example.mvvm_retrofit_imagesearchapp.room.PhotoDatabase
import com.example.mvvm_retrofit_imagesearchapp.utils.Global
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import java.lang.NumberFormatException

class DetailFragment : Fragment(R.layout.fragment_detail){

    //DetailFragmentArgs, lo crea el navigation.xml en la etiqueta <arguments>
    private val args by navArgs<DetailFragmentArgs>()

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        val binding = FragmentDetailBinding.bind(view)
        binding.apply {
            val photo = args.photo
            var room_photo : RoomUnsplashPhoto? = null
            try{
                room_photo = RoomUnsplashPhoto(photo.id!!?.toInt(),photo.description, photo.urls.full, photo.user.name)
            }catch (e:NumberFormatException){
                Toast.makeText(context, "¡ Falla la conversion !", Toast.LENGTH_LONG).show()
                Log.d("NumberFormat", e.toString())
            }

            val ro : RequestOptions = RequestOptions()


            Glide.with(this@DetailFragment)
                .load(photo.urls.regular)
                .error(R.drawable.ic_error)
                .override(Target.SIZE_ORIGINAL/3)
                .listener(object : RequestListener<Drawable> {
                    override fun onLoadFailed(e: GlideException?,model: Any?,target: Target<Drawable>?,isFirstResource: Boolean): Boolean {
                        progressBar.isVisible = false
                        return false
                    }

                    override fun onResourceReady(resource: Drawable?,model: Any?,target: Target<Drawable>?,dataSource: DataSource?,isFirstResource: Boolean): Boolean {
                        progressBar.isVisible = false
                        textviewDesc.isVisible = photo.description != null
                        textviewCreator.isVisible = true
                        return false
                    }

                })
                .into(imageView)

            textviewDesc.text = photo.description

            val uri = Uri.parse(photo.user.attributionUrl)
            val intent = Intent(Intent.ACTION_VIEW, uri)

            //set the listener to Room

            val db = context?.let {
                Room.databaseBuilder(
                    it.applicationContext,
                    PhotoDatabase::class.java, Global.databaseName
                ).build()
            }

            btnAdd.setOnClickListener(View.OnClickListener {

                GlobalScope.launch {
                    if (room_photo != null) {
                        insertPhoto(room_photo, db)
                    }else{
                        Toast.makeText(context, "El room_photo es null", Toast.LENGTH_LONG).show()
                    }
                    //Pass all the data to the RoomDatabase.
                }
            })

            textviewCreator.apply {
                text = "Photo by ${photo.user.name} on Unsplash"
                setOnClickListener {
                    context.startActivity(intent)
                }
                paint.isUnderlineText = true
            }
        }
    }

    fun insertPhoto(photo: RoomUnsplashPhoto, db: PhotoDatabase?) {
        //Pass all the data to the RoomDatabase.
        val resp = db?.photoDao()?.insertPhoto(RoomUnsplashPhoto(photo.uid,photo.description, photo.url, photo.user))
        if (resp != null) {
            if(resp.equals(photo.uid)){
                Toast.makeText(context, "Foto añadida correctamente a su diario.", Toast.LENGTH_LONG).show()
            }else{
                Toast.makeText(context, "No se ha podido añadir la foto a su diario", Toast.LENGTH_LONG).show()
            }
        }
    }
}

I hope you can help, and if like this take thanks in advance !

CodePudding user response:

I'd suggest using a String is the primary key (assuming that the id/uid is going to be unique) so use :-

@Entity
data class RoomUnsplashPhoto(
    @PrimaryKey val uid: String,
    @ColumnInfo(name = "description") val description: String?,
    @ColumnInfo(name = "url") val url: String?,
    @ColumnInfo(name="user") val user:String?,
)

Or alternately you could have an INTEGER column for the id and a String column for the uid e.g. :-

@Entity( indices = [Index(value = ["uid"], unique = true)])
data class RoomUnsplashPhoto(
    @PrimaryKey(autoGenerate = true) val id: Int,
    val uid: String,
    @ColumnInfo(name = "description") val description: String?,
    @ColumnInfo(name = "url") val url: String?,
    @ColumnInfo(name="user") val user:String?,
)
  • Note that the id column isn't really an extra column, it aliases the rowid column (a normally hidden column that always exists except for a WITHOUT ROWID table, which Room doesn't cater for anyway).
  • the index on the uid column would force the uid to be unique.

With either of the above, you do not need to convert the String to an Integer.

  • Related