从 jetpack Compose 中的 API Rest 添加列表

问题描述 投票:0回答:1

功能:这是一款卡牌游戏,其中每个玩家都有一系列卡牌,这些卡牌是我从超级英雄 API 中获取的超级英雄卡牌,所有卡牌都具有权力,这些能力定义了卡牌的力量,使玩家可以相互对抗看看谁是最好的。

使用 corrutines 我有一个超级英雄的 api,这一行是发现崩溃的地方:

fun getSuperHeroe(){
        //iniciamos una corrutina
        var lista:MutableList<SuperHero> ?= null
        viewModelScope.launch {
                try {
                    val numAleatorio = Random.nextInt(1, 732).toString()
                    val superHeroId = SuperHeroApi.retrofitService.getSuperHeroById(numAleatorio)
                    val gson = Gson()
                    var superheroResponse = gson.fromJson(superHeroId, SuperHero::class.java)
                    superHero = superheroResponse
                    lista!!.add(superHero)
                    _superHeroDeck.value = lista
                }catch (e:IOException){

                }
        }
    }

如果我只有超级英雄,一切都很好,但如果我必须添加到列表中,超级英雄就是一切开始崩溃的地方,这就是错误:

FATAL EXCEPTION: main
                                                                                                    Process: com.example.applibre, PID: 19160
                                                                                                    java.lang.NullPointerException
                                                                                                        at com.example.applibre.ui.model.HeroDeckViewModel$getSuperHeroe$1.invokeSuspend(HeroDeckViewModel.kt:71)
                                                                                                        at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
                                                                                                        at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
                                                                                                        at android.os.Handler.handleCallback(Handler.java:958)
                                                                                                        at android.os.Handler.dispatchMessage(Handler.java:99)
                                                                                                        at android.os.Looper.loopOnce(Looper.java:205)
                                                                                                        at android.os.Looper.loop(Looper.java:294)
                                                                                                        at android.app.ActivityThread.main(ActivityThread.java:8177)
                                                                                                        at java.lang.reflect.Method.invoke(Native Method)
                                                                                                        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:552)
                                                                                                        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:971)
                                                                                                        Suppressed: kotlinx.coroutines.internal.DiagnosticCoroutineContextException: [StandaloneCoroutine{Cancelling}@74f01f0, Dispatchers.Main.immediate]
2024-02-14 00:56:17.119 19160-19160 Process                 com.example.applibre                 I  Sending signal. PID: 19160 SIG: 9

我已经完美创建了数据类。我尝试在代码中放置一个列表,但这是不可能的,这或多或少是我想要的:

suspend fun getSuperHeroeById(id:String){
        //iniciamos una corrutina
        viewModelScope.launch {
            try {
                val superHeroId = SuperHeroApi.retrofitService.getSuperHeroById(id)
                val gson = Gson()
                var superheroResponse = gson.fromJson(superHeroId, SuperHeroe::class.java)
                character = superheroResponse
            }catch (e:IOException){

            }
        }
    }

    fun crearCartas(){
        viewModelScope.launch {
            try {
                val numAleatorio = Random.nextInt(1, 732).toString()
                var superHeroe = getSuperHeroeById(numAleatorio)
                val numAleatorio2 = Random.nextInt(1, 732).toString()
                var superHeroe2 = getSuperHeroeById(numAleatorio2)
                var superHeroes:MutableList<SuperHeroe> = mutableListOf()
            }catch (e:IOException){

            }
        }
    }

解释:为每个玩家放置一个超级英雄(卡)列表。

这是viewModel的实际代码:

class HeroDeckViewModel:ViewModel(){
    private val _player = MutableLiveData<Player>()

    private val _nickNamePlayer = MutableLiveData<String>()
    val nickNamePlayer1: LiveData<String> = _nickNamePlayer

    private val _characterDeck  = MutableStateFlow<List<SuperHeroe>>(emptyList())
    val characterDeck: StateFlow<List<SuperHeroe>> = _characterDeck

    var character by mutableStateOf(
        SuperHeroe(
            response = "",
            id = 0,
            name = "",
            powerStats = PowerStats(0, 0, 0, 0, 0, 0),
            biography = Biography("", "", listOf(), "", "", "", ""),
            appearance = Appearance("", "", listOf(), listOf(), "", ""),
            work = Work("", ""),
            connections = Connections("", ""),
            image = Image("")
        )
    )
    private set;


    init {
        getSuperHeroe()
    }

    fun onPlayer(nickName:String){
        _nickNamePlayer.value = nickName
    }


    fun getSuperHeroe(){
        //iniciamos una corrutina
        viewModelScope.launch {
                try {
                    val numAleatorio = Random.nextInt(1, 732).toString()
                    val superHeroId = SuperHeroApi.retrofitService.getSuperHeroById(numAleatorio)
                    val gson = Gson()
                    var superheroResponse = gson.fromJson(superHeroId, SuperHeroe::class.java)
                    character = superheroResponse
                }catch (e:IOException){

                }
        }
    }

    /**
     * calcula el poder de los personajes
     */
    private fun checkPuntos(){
        val powerStats = character.powerStats
        val totalPowers = powerStats.power + powerStats.combat + powerStats.durability + powerStats.speed
        + powerStats.strength + powerStats.intelligence

        val powerPercentage = powerStats.power.toDouble() / totalPowers * 10
        val combatPercentage = powerStats.combat.toDouble() / totalPowers * 15
        val durabilityPercentage = powerStats.durability.toDouble() / totalPowers * 15
        val speedPercentage = powerStats.speed.toDouble() / totalPowers * 15
        val strengthPercentage = powerStats.strength.toDouble() / totalPowers * 20
        val intelligencePercentage = powerStats.intelligence.toDouble() / totalPowers * 25

        /*
        * cada turno da mana
        * y empiezas con uno de mana
        * cada carta tiene su propio coste de mana
        * */


    }

}

这是数据类:


data class Appearance(
    val gender: String,
    val race: String,
    val height: List<String>,
    val weight: List<String>,
    @SerializedName("eye-color")
    val eyeColor: String,
    @SerializedName("hair-color")
    val hairColor: String
)
data class Biography(
    @SerializedName("full-name")
    val fullName: String,
    @SerializedName("alter-egos")
    val alterEgos: String,
    val aliases: List<String>,
    @SerializedName("place-of-birth")
    val placeOfBirth: String,
    @SerializedName("first-appearance")
    val firstAppearance: String,
    val publisher: String,
    val alignment: String
)
data class Connections(
    @SerializedName("group-affilation")
    val groupAffiliation: String,
    val relatives: String
)
class Deck {

    companion object {
        // The list to store the deck of cards
        val listaCharacters: ArrayList<SuperHeroe> = ArrayList()

        /**
         * Genera un número aleatorio en el rango de 1 a 731
         * que son todos los posibles id
         */
        fun obtenerNumeroAleatorio(): Int {
            return Random.nextInt(1, 732)
        }

        fun shuffle() {
            listaCharacters.shuffle()
        }

        /**
         * Gets the last card from the deck.
         *
         * @return The last card in the deck.
         */
        fun getSuperHero(): SuperHeroe {
            val carta = listaCharacters.last()
            listaCharacters.removeLast()
            return carta
        }




        /**
         * Gets the total number of cards in the deck.
         *
         * @return The total number of cards in the deck.
         */
        fun getCardsTotal(): Int {
            return listaCharacters.size
        }

    }
}
datadata class Image(val url:String)
data class Player(
    var vida:Int,
    var nikeName:String,
    var characters:MutableList<SuperHeroe>
)
data class PowerStats(
    val intelligence: Int,
    val strength: Int,
    val speed: Int,
    val durability: Int,
    val power: Int,
    val combat: Int
)
data class SuperHeroe (
    val response:String,
    val id:Int,
    val name:String,
    @SerializedName("powerstats")
    val powerStats:PowerStats,
    val biography:Biography,
    val appearance:Appearance,
    val work:Work,
    val connections: Connections,
    val image:Image,
)
data class Work(
    val occupation: String,
    @SerializedName("base")
    val baseOfOperation: String
)
object SuperHeroApi {

   val retrofitService:SuperHeroApiService by lazy {
       retrofit.create(SuperHeroApiService::class.java)
   }
}
const val BASE_URL =
    "https://www.superheroapi.com/api.php/934555588123234/"


val retrofit: Retrofit = Retrofit.Builder()
    .addConverterFactory(ScalarsConverterFactory.create())
    .baseUrl(BASE_URL)
    .build()


interface SuperHeroApiService{

    /**
     * Obtiene todo del personaje
     */
    @GET("{id}")
    suspend fun getSuperHeroById(@Path("id") id: String): String


    /**
     * @return devuelve el id del personaje
     */
    @GET("search/{name}")
    suspend fun getSuperHeroByName(@Path("name") name: String): String
}
@OptIn(ExperimentalMaterial3Api::class)
@Preview
@Composable
fun visualizar(){
    screen()
}
/*Contiene toda la pantalla*/
@ExperimentalMaterial3Api
@Composable
fun screen(){
    val heroDeckViewModel:HeroDeckViewModel = HeroDeckViewModel()
    Scaffold(
        topBar = {
            TopAppBar(
                colors = topAppBarColors(
                    containerColor = MaterialTheme.colorScheme.primaryContainer,
                    titleContentColor = MaterialTheme.colorScheme.primary,
                ),
                title = {
                    Text("Hero-Deck")
                }
            )
        },
        bottomBar = {
            BottomAppBar(
                containerColor = MaterialTheme.colorScheme.primaryContainer,
                contentColor = MaterialTheme.colorScheme.primary,
            ) {
                Button(onClick = { heroDeckViewModel.getSuperHeroe() }) {
                    Text(
                        modifier = Modifier
                            .fillMaxWidth(),
                        textAlign = TextAlign.Center,
                        text = "Bottom app bar",
                    )
                }
            }
        },
    ) { innerPadding ->
        Column(
            modifier = Modifier
                .padding(innerPadding),
            verticalArrangement = Arrangement.spacedBy(16.dp),
        ) {
            LazyColumn{
                item { SuperHeroCard(character = heroDeckViewModel.character) }
            }

        }
    }
}

/**
 * imprime la carta
 */
@Composable
fun SuperHeroCard(character: SuperHeroe){
    var showText by remember { mutableStateOf(false) }

    val urlImagen = character.image.url
    AsyncImage(
        model = ImageRequest.Builder(context = LocalContext.current)
            .data(urlImagen)
            .build(),
        contentDescription = "SuperHero",
        contentScale = ContentScale.Crop,
        modifier = Modifier.fillMaxWidth()
    )

    Button(onClick = { showText = !showText }, modifier = Modifier.padding(start = 150.dp)) {
        Text(if (showText) "Ocultar" else "Ver más")
    }

    if (showText) {
        mostrar(character)
    }
}

@Composable
fun mostrar(character: SuperHeroe){
    Text(text = character.name)
    Text(text = character.powerStats.toString())
}


class MainActivity : ComponentActivity() {
    @OptIn(ExperimentalMaterial3Api::class)
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            AppLibreTheme {
                // A surface container using the 'background' color from the theme
                Surface(modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background) {
                    screen()
                }
            }
        }
    }
}

这是所有代码,API 是这个:https://www.superheroapi.com/

如果您想更好地下载代码,您还可以找到该应用程序的链接:https://github.com/jorgitorr/HeroDeck

我希望每个玩家的列表中都有不同的超级英雄,如下所示:(但正在工作)

fun getSuperHeroe(){
        //iniciamos una corrutina
        var lista:MutableList<SuperHero> ?= null
        viewModelScope.launch {
                try {
                    val numAleatorio = Random.nextInt(1, 732).toString()
                    val superHeroId = SuperHeroApi.retrofitService.getSuperHeroById(numAleatorio)
                    val gson = Gson()
                    var superheroResponse = gson.fromJson(superHeroId, SuperHero::class.java)
                    superHero = superheroResponse
                    lista!!.add(superHero)
                    _superHeroDeck.value = lista
                }catch (e:IOException){

                }
        }
    }
multithreading api kotlin android-jetpack-compose retrofit
1个回答
0
投票

您可以这样声明您的列表:

var lista:MutableList<SuperHero> ?= null

然后,您可以像这样访问它:

lista!!.add(superHero)

您正在使用

!!
,它是 not-null 断言运算符。它尝试将可空类型
MutableList<SuperHero>?
转换为不可空类型
MutableList<SuperHero>
。如果
lista
为空,它将抛出
NullPointerException
,这正是您的情况所发生的情况。

不要将

alist
初始化为
null
,而是将其初始化为空列表:

val lista: MutableList<SuperHero> = mutableListOf()
© www.soinside.com 2019 - 2024. All rights reserved.