-1

I'm currently making a sample project about diagrams. I'm starting to use MVVM architecture recently, and I got stuck when the response is null. I also checked the Mutable Live Data to make sure that it is calling the API. Here's some of my code and the error-tag:

Model.kt

data class Model(
    @SerializedName("FID") val FID: Int,
    @SerializedName("region") val region: String,
    @SerializedName("positive") val positive: Float
) {
}

ModelWrap.kt

data class ModelWrap(@SerializedName("samplesAPI") val attributes: Model){
}

ApiClient.kt

object ApiClient {
    var retrofitService: ApiInterface? = null
    const val BASE_URL = "https://sampleapi.../"

    fun getApiSample() : ApiInterface {
        if (retrofitService == null){
            val retrofit = Retrofit.Builder()
                .baseUrl(BASE_URL)
                .addConverterFactory(GsonConverterFactory.create())
                .build()
            retrofitService = retrofit.create(ApiInterface::class.java)
        }
        return retrofitService!!
    }
}

ApiInterface.kt

interface ApiInterface {
    @GET("samples")
    fun getSampleData(): Call<List<ModelWrap>>
}

MainViewModel.kt

class MainViewModelconstructor(private val repository: ModelRepository) : ViewModel(){
    val sampleList= MutableLiveData<List<ModelWrap>>()
    val errorMessage = MutableLiveData<String>()

    fun getSampleData(pieChart: PieChart){
        val response = repository.getSampleData()
        response.enqueue(object : Callback<List<ModelWrap>> {
            override fun onResponse(
                call: Call<List<ModelWrap>>,
                response: Response<List<ModelWrap>>
            ) {
                sampleList.postValue(response.body())
                
            }
            override fun onFailure(call: Call<List<ModelWrap>>, t: Throwable) {
                errorMessage.postValue(t.message)
            }

        })
    }
}

MainViewModelFactory.kt

class MainViewModelFactoryconstructor(private val repository: MainRepository) : ViewModelProvider.Factory {
    override fun <T : ViewModel?> create(modelClass: Class<T>): T {
        return  if (modelClass.isAssignableFrom(MainViewModel::class.java)){
            MainViewModel(this.repository) as T
        } else {
            throw IllegalArgumentException("Sample ViewModel Not Found")
        }
    }
}

MainRepository.kt

class MainRepository constructor(private val retrofitService: ApiInterface){
    fun getSampleData() = retrofitService.getSampleData()
}

MainActivity.kt

class MainActivity : AppCompatActivity() {
    private lateinit var pieChart: PieChart

    lateinit var sampleViewModel: MainViewModel

    private val sampleService = ApiClient.getApiSample()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        pieChart = findViewById(R.id.PieChart)

        sampleViewModel= ViewModelProvider(this, MainViewModelFactory(MainRepository(sampleService))).get(MainViewModel::class.java)

        getPieChart(pieChart)

    }

    private fun getPieChart(pieCharts: PieChart) {
        mainViewModel.mainList.observe(this, Observer {
            Log.d("TAG sample" , "onCreate PieChart: $it")
Log.d("Tag Samples Response" , response.body().toString())
                    if (it != null) {
                        val sampleEntries: List<PieEntry> = ArrayList()
                        for ((attributes) in it!!) {
                            sampleEntries.toMutableList()
                                .add(PieEntry(attributes.positive, attributes.region))
    
        //........................................................................
    
                            val description = Description()
                            description.text = "Samples Data"
                            pieChart.description = description
                            pieChart.invalidate()
                        }
                    }
        })
        mainViewModel.errorMessage.observe(this, Observer {  })
        mainViewModel.getSampleData(pieCharts)
    }
}

and Lastly, here's some or log message:

V/InputMethodManager: Starting input: tba=android.view.inputmethod.EditorInfo@8b795c0 nm : com.example.diargram ic=null
D/Tag Sample Response: null
D/TAG Sample: onCreate PieChart: null
E/libc: Access denied finding property "ro.serialno"
V/StudioTransport: Agent command stream started.
V/StudioTransport: Transport agent connected to daemon.

I would appreciate it if someone can help me :D, Thank you

XVallerie
  • 141
  • 2
  • 11
  • can you send a sample of your json response – The Codepreneur May 04 '21 at 09:45
  • The body may be null because of serialization errors in the background. What retrofit does is it returns null and no error message – The Codepreneur May 04 '21 at 09:46
  • @ebs237 here's my json `[ { "samplesAPI": { "FID": 11, "region": "seoul", "positive": 406205 } }, { "samplesAPI": { "FID": 12, "region": "hoseong", "positive": 277553 } } ]` – XVallerie May 04 '21 at 09:53
  • @ebs237 anyway, i already get the response, but it won't show in my pie chart, any solution? – XVallerie May 04 '21 at 09:55
  • for proper implementation MVVM keep a livedata variable to get the value of response and update the data on the pie chart in the MAIN activity – The Codepreneur May 04 '21 at 10:30
  • @ebs237 I got it, but to do that, I need to call the live data from the viewmodel to mainactivity right? then I can pass the data to pieChart in mainactivity? How to do that?, I decided to go that way like the one I posted above because I'm confused, is there any example that can guide me? Thank you anyway – XVallerie May 04 '21 at 10:33
  • @ebs237 I've tried to do exactly as u suggested but still, the pie chart doesn't show anything – XVallerie May 04 '21 at 10:38
  • check this out https://learntodroid.com/consuming-a-rest-api-using-retrofit2-with-the-mvvm-pattern-in-android/ – The Codepreneur May 04 '21 at 10:39
  • if you are still facing some issues let me know – The Codepreneur May 04 '21 at 10:40
  • @ebs237 I've edited my ViewModel and MainActivity, is there anything I need to fix? – XVallerie May 04 '21 at 10:40
  • @ebs237 basically, if using recyclerview or any kind of listview we will create an adapter class, and binding it with the ActivityBinding, but here with PieChart, I just don't know how to bind it with MutableLiveData – XVallerie May 04 '21 at 10:42
  • When you are using it export the use a method to return a livedata and in the main activity , observe the datachange if the data is different from null set the piechart description to the requested information in the response – The Codepreneur May 04 '21 at 10:48
  • When you are using it, use a method to return a livedata and in the main activity , observe the data change if the data is different from null set the piechart description to the requested information in the response – The Codepreneur May 04 '21 at 10:50
  • @ebs237 Sorry, I don't understand, do you have any examples? – XVallerie May 04 '21 at 10:54
  • @ebs237 based on the code above, and based on my logcat, the sampleEntries does not get any data. the logcat is like : `D/sampleEntriesCovid: [] D/sampleEntriesCovid: []` but the response of "it" is like : `D/TAG Samples: onCreate PieChart: [SampleWrap(attributes=Samples(FID=11, positive=31, region=seoul,.... and etc` – XVallerie May 04 '21 at 10:56
  • It is possible that you ask another question and upload the code for this to the question so that I can see or better still edit this an upload the code. – The Codepreneur May 04 '21 at 11:00
  • @ebs237 sure here's the new one https://stackoverflow.com/q/67383706/11708862 – XVallerie May 04 '21 at 11:16
  • can't find the page – The Codepreneur May 04 '21 at 12:45
  • @ebs237 it's okay, I already find the solution Thank you for your guide anyway – XVallerie May 04 '21 at 13:28

1 Answers1

0

Finally, I found a solution for my problem:

  1. I type the wrong endpoint inside the interface class and it should be like this:

interface ApiInterface { @GET("sample") fun getSampleData(): Call<List> }

  1. When it comes to assigning the livedata to the view, based on my JSON I should call ArrayList instead of List
  2. List item

Before :

val sampleEntries: List = ArrayList()

After :

val sampleEntries: ArrayList<PieEntry> = ArrayList()
XVallerie
  • 141
  • 2
  • 11