Search code examples
androidrestkotlinretrofitretrofit2

How to make API calls. I am a beginner


I want to make an app that shows a funfact/joke and there's a button that refreshes the activity to load another funfact/joke.

I have made the data class, retrofit object and the interface and made the layout and also have written some code in the main activity. The app runs, however the funfact/joke isn't loaded on the activity.

Please help, I am a beginner.

Here are the codes:

Data Class:

data class FunFact(
    val joke: String
)

Retrofit Object:

object RetrofitInstance {

    val api: FunFactInterface by lazy {
        Retrofit.Builder()
            .baseUrl("https://geek-jokes.sameerkumar.website")
            .addConverterFactory(GsonConverterFactory.create())
            .build()
            .create(FunFactInterface::class.java)
    }
}

Interface:

interface FunFactInterface {

    @GET("/api?format=json")
    suspend fun getFacts(): Response<FunFact>
}

Main Activity:

class MainActivity : AppCompatActivity() {

    var binding: ActivityMainBinding? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)


        GlobalScope.launch {
            loadData()
        }

    }


    private suspend fun loadData() {

        val dataApi = RetrofitInstance.api
        val results = dataApi.getFacts()
        if(results!=null){
            if (binding != null) {
                binding!!.textView.text= results.toString()
            }

        }
    }
}

XML Layout:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="the fact"
        android:textSize="20dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Another Fact"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/textView" />

</androidx.constraintlayout.widget.ConstraintLayout>

The XML Design is this: APP Design

Edit/Update: Thanks to you guys the app is getting response. I removed the keyword suspend from the functions and also added code to handle onFailure scenario. Also removed "val" before binding in mainActivity as suggested.

Updated Code:

class MainActivity : AppCompatActivity() {

    var binding: ActivityMainBinding? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding!!.root)


        loadData()
        
        binding!!.button.setOnClickListener{
            loadData()
        }


    }


    private fun loadData() {

        val dataApi = RetrofitInstance.api
        var results = dataApi.getFacts()
        if (results!=null){

            results.enqueue(object: Callback<FunFact>{
                override fun onResponse(call: Call<FunFact>, response: Response<FunFact>) {
                    if(response!=null){
                        binding!!.textView.text= response.body().toString()

                    }
                }

                override fun onFailure(call: Call<FunFact>, t: Throwable) {
                    Toast.makeText(this@MainActivity,"Failure of response from API", Toast.LENGTH_SHORT)
                        .show()
                }
            })

        }



    }
}

The app runs and the joke is loaded, the format of the joke is little different than desired. Any kind of help is truly appreciated.

This is the image of the response that I got, I want to remove "funfact" and "joke=" : the app image


Solution

  • If the code in MainActivity is correct, then you're not setting the value of the instance variable binding 'cause you're creating another local variable with the same name in the Activitys onCreate

    Here's something you can do

    class MainActivity : AppCompatActivity() {
    
        private lateinit var binding: ActivityMainBinding
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            // set the value of the instance variable
            binding = ActivityMainBinding.inflate(layoutInflater)
            setContentView(binding.root)
    
            GlobalScope.launch {
                loadData()
            }
        }
    
    
        private suspend fun loadData() = withContext(Dispatchers.Main) {
            val dataApi = RetrofitInstance.api
            val results = dataApi.getFacts()
    
            binding.textView.text = results.body()?.joke
        }
    }