Home > Blockchain >  GET request in retrofit in android is not working
GET request in retrofit in android is not working

Time:01-23

I am trying to learn compose and retrofit and for that I am developing a very easy app, fetching jokes from a public API and showing them in a lazy list. But it is not working and I am not able to see any jokes. I am new to Kotlin and Jetpack compose. Please help me debug this.

I have a joke class

data class Joke(
    val id: Int,.
    val punchline: String,
    val setup: String,
    val type: String
)

This is the API I am GETing from: https://official-joke-api.appspot.com/jokes/:id This is the response:

{"type":"general","setup":"What did the fish say when it hit the wall?","punchline":"Dam.","id":1}

This is the retrofit api service:


const val BASE_URL = "https://official-joke-api.appspot.com/"

interface JokeRepository {

    @GET("jokes/{id}")
    suspend fun getJoke(@Path("id") id: String ) : Joke
    companion object {
        var apiService: JokeRepository? = null
        fun getInstance(): JokeRepository {
            if (apiService == null) {
                apiService = Retrofit.Builder()
                    .baseUrl(BASE_URL)
                    .addConverterFactory(GsonConverterFactory.create())
                    .build().create(JokeRepository::class.java)
            }
            return apiService!!
        }
    }
}

This is the Jokes view model:

class JokeViewModel : ViewModel() {
    private val _jokeList = mutableListOf<Joke>()
    var errorMessage by mutableStateOf("")
    val jokeList: List<Joke> get() = _jokeList

    fun getJokeList() {
        viewModelScope.launch {
            val apiService = JokeRepository.getInstance()
            try {
                _jokeList.clear()
//                for(i in 1..100) {
//                    var jokeWithId = apiService.getJoke(i.toString())
//                    _jokeList.add(jokeWithId)
//                    Log.d("DEBUGGG", jokeWithId.setup)
//                }
                var joke = apiService.getJoke("1")
                _jokeList.add(joke)

            }
            catch (e: Exception) {
                errorMessage = e.message.toString()
            }
        }
    }
}

This is the Main Activity

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {

        val jokeViewModel = JokeViewModel()
        super.onCreate(savedInstanceState)
        setContent {
            HasyamTheme {
                // A surface container using the 'background' color from the theme
                Surface(
                    modifier = Modifier.fillMaxSize(),
                    color = MaterialTheme.colorScheme.background
                ) {
                    JokeView(jvm = jokeViewModel)
                }
            }
        }
    }
}

This is the Joke Component and view

@Composable
fun JokeView(jvm: JokeViewModel) {
    LaunchedEffect(Unit, block = {
        jvm.getJokeList()
    })
    
    Text(text = jvm.errorMessage)
    
    LazyColumn() {
        items(jvm.jokeList) {
            joke -> JokeComponent(joke)
        }
    }

}



@OptIn(ExperimentalMaterial3Api::class)

@Composable
fun JokeComponent(joke: Joke) {

    var opened by remember { mutableStateOf(false)}

    Column(
        modifier = Modifier.padding(15.dp)
    ) {
        Card(
            modifier = Modifier
                .fillMaxWidth()
                .clickable { },
            elevation = CardDefaults.cardElevation(
                defaultElevation = 5.dp
            ),

            onClick = { opened = !opened}

        ) {
            Text(modifier = Modifier.padding(15.dp), text = joke.setup)
        }

        if (opened) {
            Text(modifier = Modifier.padding(15.dp), text = joke.punchline)
        }
    }
}

Thank you so much

CodePudding user response:

The issue here is that you are not using stateFlow. The screen is not recomposed so your LazyColumn is not recreated with the updated values.

ViewModel

class JokeViewModel : ViewModel() {
    var errorMessage by mutableStateOf("")
    private val _jokes = MutableStateFlow(emptyList<Joke>())
    val jokes = _jokes.asStateFlow()

    fun getJokeList() {
        viewModelScope.launch {
            val apiService = JokeRepository.getInstance()
            try {
                var jokes = apiService.getJoke("1")
                _jokes.update { jokes }

            } catch (e: Exception) {
                errorMessage = e.message.toString()
            }
        }
    }
}

Joke View


@Composable
fun JokeView(jvm: JokeViewModel) {
    
    val jokes by jvm.jokes.collectAsState()

    LaunchedEffect(Unit, block = {
        jvm.getJokeList()
    })

    Text(text = jvm.errorMessage)

    LazyColumn {
        items(jokes) {
                joke -> JokeComponent(joke)
        }
    }
}


You should read the following documentation about states : https://developer.android.com/jetpack/compose/state

  • Related