user3761485
user3761485

Reputation: 61

Unable to invoke no-args constructor for retrofit2.Call MVVM Coroutines Retrofit

I want to use coroutines in my project only when I use coroutines I get the error :Unable to invoke no-args constructor. I don't know why it's given this error. I am also new to coroutines.

here is my apiclient class:

class ApiClient {

    val retro = Retrofit.Builder()
        .baseUrl(Constants.BASE_URL)
        .addConverterFactory(GsonConverterFactory.create())
        .build()
}

Here is my endpoint class:

@GET("v2/venues/search")
  suspend   fun get(
        @Query("near") city: String,
        @Query("limit") limit: String = Constants.limit,
        @Query("radius") radius: String = Constants.radius,
        @Query("client_id") id: String = Constants.clientId,
        @Query("client_secret") secret: String = Constants.clientSecret,
        @Query("v") date: String
    ): Call<VenuesMainResponse>

my Repository class:

class VenuesRepository() {

    private val _data: MutableLiveData<VenuesMainResponse?> = MutableLiveData(null)
    val data: LiveData<VenuesMainResponse?> get() = _data


   suspend fun fetch(city: String, date: String)  {

        val retrofit = ApiClient()
        val api = retrofit.retro.create(VenuesEndpoint::class.java)

        api.get(
            city = city,
            date = date
        ).enqueue(object : Callback<VenuesMainResponse>{

            override fun onResponse(call: Call<VenuesMainResponse>, response: Response<VenuesMainResponse>) {

                val res = response.body()
                if (response.code() == 200 && res != null) {

                    _data.value = res

                } else {

                    _data.value = null
                }
            }

            override fun onFailure(call: Call<VenuesMainResponse>, t: Throwable) {
                _data.value = null
            }
        })
    }

}

my ViewModel class:

class VenueViewModel( ) : ViewModel() {

    private val repository = VenuesRepository()

    fun getData(city: String, date: String): LiveData<VenuesMainResponse?> {
        viewModelScope.launch {
            try {
                repository.fetch(city, date)

            } catch (e: Exception) {
                Log.d("Hallo", "Exception: " + e.message)
            }
        }
        return repository.data
    }

}

part of activity class:

class MainActivity : AppCompatActivity(){
    private lateinit var venuesViewModel: VenueViewModel
    private lateinit var adapter: HomeAdapter
    private var searchData: List<Venue>? = null
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val editText = findViewById<EditText>(R.id.main_search)
        venuesViewModel = ViewModelProvider(this)[VenueViewModel::class.java]
        venuesViewModel.getData(
            city = "",
            date = ""
        ).observe(this, Observer {

            it?.let { res ->
                initAdapter()
                rv_home.visibility = View.VISIBLE
                adapter.setData(it.response.venues)
                searchData = it.response.venues
                println(it.response.venues)
            }
        })

this is my VenuesMainResponse data class

data class VenuesMainResponse(
    val response: VenuesResponse
)

Upvotes: 0

Views: 2001

Answers (1)

mehul bisht
mehul bisht

Reputation: 742

I think the no-args constructor warning should be related to your VenuesMainResponse, is it a data class? You should add the code for it as well and the complete Log details

Also, with Coroutines you should the change return value of the get() from Call<VenuesMainResponse> to VenuesMainResponse. You can then use a try-catch block to get the value instead of using enqueue on the Call.

Check this answer for knowing about it and feel free to ask if this doesn't solve the issue yet :)

UPDATE

Ok so I just noticed that it seems that you are trying to use the foursquare API. I recently helped out someone on StackOverFlow with the foursquare API so I kinda recognize those Query parameters and the Venue response in the code you provided above.

I guided the person on how to fetch the Venues from the Response using the MVVM architecture as well. You can find the complete code for getting the response after the UPDATE block in the answer here.

This answer by me has code with detailed explanation for ViewModel, Repository, MainActivity, and all the Model classes that you will need for fetching Venues from the foursquare API.

Let me know if you are unable to understand it, I'll help you out! :)

RE: UPDATE

So here is the change that will allow you to use this code with Coroutines as well.

Repository.kt

class Repository {

    private val _data: MutableLiveData<mainResponse?> = MutableLiveData(null)
    val data: LiveData<mainResponse?> get() = _data

    suspend fun fetch(longlat: String, date: String) {

        val retrofit = Retro()
        val api = retrofit.retro.create(api::class.java)
   
        try {

            val response = api.get(
                longLat = longlat,
                date = date
            )
            _data.value = response
        } catch (e: Exception) {

            _data.value = null
        }
    }
}

ViewModel.kt

class ViewModel : ViewModel() {

    private val repository = Repository()

    val data: LiveData<mainResponse?> = repository.data

    fun getData(longLat: String, date: String) {

        viewModelScope.launch {

            repository.fetch(longLat, date)
        }
    }
}

api.kt

interface api {

    @GET("v2/venues/search")
    suspend fun get(
        @Query("ll") longLat: String,
        @Query("client_id") id: String = Const.clientId,
        @Query("client_secret") secret: String = Const.clientSecret,
        @Query("v") date: String
    ): mainResponse
}

MainActivity.kt

private val viewModel by viewModels<ViewModel>()

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

    viewModel.getData(
        longLat = "40.7,-74",
        date = "20210718" // date format is: YYYYMMDD
    )

    viewModel.data
        .observe(this, Observer {

            it?.let { res ->

                res.response.venues.forEach { venue ->

                    val name = venue.name

                    Log.d("name ",name)
                }
            }
        })    

    }
}

Upvotes: 1

Related Questions