功能:这是一款卡牌游戏,其中每个玩家都有一系列卡牌,这些卡牌是我从超级英雄 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){
}
}
}
您可以这样声明您的列表:
var lista:MutableList<SuperHero> ?= null
然后,您可以像这样访问它:
lista!!.add(superHero)
您正在使用
!!
,它是 not-null 断言运算符。它尝试将可空类型 MutableList<SuperHero>?
转换为不可空类型 MutableList<SuperHero>
。如果 lista
为空,它将抛出 NullPointerException
,这正是您的情况所发生的情况。
不要将
alist
初始化为 null
,而是将其初始化为空列表:
val lista: MutableList<SuperHero> = mutableListOf()