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.