如何将 String 转换为 Int,以便用作 RoomDatabase 的 uid

How to convert String into an Int, in order to used as uid of RoomDatabase

我正在开发一个 Kotlin 应用程序,我尝试在其中实现 Room 并与 API 连接并重新运行不同的猫图像,我将其加载到应用程序中。

我的问题是因为我有 2 个数据模型:一个用于 API 连接,另一个用于 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?,
)

和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"
    }
}

因此,正如您所见,当我尝试将 API 的 id(字符串)转换为我的房间模型的 uid 时,问题就来了,它需要是 Int 或 Long,我猜测

错误如下:

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

最后我尝试实现的片段是这样的:

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()
            }
        }
    }
}

希望对您有所帮助,如果喜欢请提前致谢!

我建议使用字符串作为主键(假设 id/uid 是唯一的)所以使用 :-

@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?,
)

或者您可以为 id 设置一个 INTEGER 列,为 uid 设置一个字符串列,例如:-

@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?,
)
  • 请注意,id 列并不是真正的额外列,它是 rowid 列的别名(一个通常隐藏的列,除了 WITHOUT ROWID table, 哪个 Room 无论如何都不适合)。
  • uid 列上的索引将强制 uid 是唯一的。

使用上述任一方法,您无需将字符串转换为整数。