Post method using retrofit not working, logcat saying its null - android-studio

I'm trying to send some data to my server, it says that data was sent however when I check the website nothing happens. In the logcat it says that mView is null.
I tried different methods in order to send data to the server, but it always appears the same error.
Here is the model that is in my server:
Here are my classes
The endpoint:
interface Endpoint {
#GET("ocorrenciasapi")
fun getPosts():Call<List<Ocorrencia>>
#POST("ocorrenciasapi")
#FormUrlEncoded
open fun savePost(
#Field("dispositivo") dispositivo: String?,
#Field("dataOcorrencia") dataOcorrencia: String?,
#Field("latitude") latitude: String?,
#Field("longitude") longitude: String?,
#Field("azimute") azimute: String?,
#Field("fotografia") fotografia: String?,
#Field("nomeFotografia") nomeFotografia: String?,
#Field("estado") estado: String?
): Call<Ocorrencia?>?
}
networkutils class:
class NetworkUtils {
companion object{
fun getRetrofitInstance(path : String) : Retrofit{
return Retrofit.Builder()
.baseUrl(path)
.addConverterFactory(GsonConverterFactory.create())
.build()
}
}
ocorrencia class:
data class Ocorrencia (
#SerializedName("dispositivo") val dispositivo: String?,
#SerializedName("dataOcorrencia") val dataOcorrencia: String?,
#SerializedName("latitude") val latitude: String?,
#SerializedName("longitude") val longitude: String?,
#SerializedName("azimute") val azimute: String?,
#SerializedName("fotografia") val fotografia: String?,
#SerializedName("nomeFotografia") val nomeFotografia: String?,
#SerializedName("estado") val estado: String?
)
Here is the method that sends it:
fun sendPost(){
val retrofitClient = NetworkUtils
.getRetrofitInstance("https://adamastor.ipt.pt/appFogos/api/")
val endpoint = retrofitClient.create(Endpoint::class.java)
val callback = endpoint.savePost(
"teste1",
"2020-06-12T12:26:48.0095273",
"37.089940",
"-7.800357",
"43",
"R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7",
"teste1Foto",
"aceite")
callback?.enqueue(object : retrofit2.Callback<Ocorrencia?>{
override fun onFailure(call: Call<Ocorrencia?>, t: Throwable) {
Toast.makeText(baseContext, t.message, Toast.LENGTH_LONG).show()
}
override fun onResponse(call: Call<Ocorrencia?>, response: Response<Ocorrencia?>) {
Toast.makeText(applicationContext,"A ocorrĂȘncia foi enviada", Toast.LENGTH_LONG).show()
}
})
}

Related

How to change retrofit #GET programatically

I have a app where I use youtube api and make a get request using retrofit, now I want to get a list of videos for a specific keyword, but for that I have to use a different get req everytime so how can I change the get request programatically
Code for calling API
private fun getVideosList() {
val videos = RetrofitInstance.youtubeapi.getYoutubeVideos()
videos.enqueue(object : Callback<YoutubeAPIData?> {
override fun onResponse(call: Call<YoutubeAPIData?>, response: Response<YoutubeAPIData?>) {
val videosList = response.body()?.items
if (videosList != null) {
for(video in videosList) {
Log.d("title", video.snippet.title)
}
}
}
override fun onFailure(call: Call<YoutubeAPIData?>, t: Throwable) {
Toast.makeText(applicationContext, "Unable to fetch results!", Toast.LENGTH_SHORT).show()
Log.d("APIError",t.toString())
}
})
}
Retrofit Instance
object RetrofitInstance {
const val BASE_URL = "https://www.googleapis.com/youtube/v3/"
private val retrofit by lazy {
Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build()
}
val youtubeapi: YoutubeListApi by lazy {
retrofit.create(YoutubeListApi::class.java)
}}
Code for API interface
interface YoutubeListApi {
#GET("search?part=snippet&q=eminem&key=*my_key*")
fun getYoutubeVideos(): Call<YoutubeAPIData>}
Now what I want is to change the #GET("search?part=snippet&q=eminem&key=my_key") in the api interface so that if the keyword is eminem it should be search?part=snippet&q=eminem&key=my_key
and if keyword is dog it should be search?part=snippet&q=dogkey=my_key
Why not use #Query from retrofit?
You could redefine your interface to:
interface YoutubeListApi {
#GET("search")
fun getYoutubeVideos(
#Query("part") part: String,
#Query("q") query: String,
#Query("key") key: String,
): Call<YoutubeAPIData>
}
and then you can call it like getYoutubeVideos("snippets", "eminem", "your key") or getYoutubeVideos("snippets", "dog", "your key").
I think you can even hardcode some values in the URL if you want, but honestly I think you can just use kotlin default values:
interface YoutubeListApi {
#GET("search")
fun getYoutubeVideos(
#Query("q") query: String,
#Query("part") part: String = "snippet",
#Query("key") key: String = "your key",
): Call<YoutubeAPIData>
}
and just pass the query getYoutubeVideos("eminem"). I haven't double checked this, but I think it could work.

I face this error java.lang.IllegalArgumentException: Could not locate call adapter for class java.lang.Object

I am new with MVVM in kotlin, I want to fetch some data using retrofit and show this in textview but I can't fetch this. In this app first time, I am using the android jetpack component. I tried a lot of times but I can't solve this error. My code in below
MainActivity.kt
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val repository = Repository()
val viewModelFactory = MainViewModelFactory(repository)
viewModel = ViewModelProvider(this, viewModelFactory).get(MainViewModel::class.java)
viewModel.getEmployeeData()
viewModel.repoResponse.observe(this, Observer { response ->
if (response.isSuccessful) {
Log.d("Response", response.body()?.employee_id.toString())
Log.d("Response", response.body()?.employee_name.toString())
Log.d("Response", response.body()?.employee_age.toString())
Log.d("Response", response.body()?.employee_salary.toString())
name.text = response.body()?.employee_name!!
} else {
Log.d("Response", response.errorBody().toString())
name.text = response.code().toString()
}
})
}
MainViewModelFactory.kt
class MainViewModelFactory(private val repository: Repository):ViewModelProvider.Factory {
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
return MainViewModel(repository) as T
}
MainViewModel.kt
class MainViewModel(private val repository: Repository):ViewModel() {
val repoResponse:MutableLiveData<Response<Employee>> = MutableLiveData()
fun getEmployeeData(){
viewModelScope.launch {
val response = repository.getEmployeeData()
repoResponse.value = response
}
}
ApiClient.kt
object ApiClient {
private val retrofit by lazy{
Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build()
}
val api:Api by lazy {
retrofit.create(Api::class.java)
}
Api.kt
public interface Api {
#GET("api/v1/employee/1")
suspend fun getEmployeeData():Response<Employee>
}
Repository.kt
class Repository {
suspend fun getEmployeeData():Response<Employee>{
return ApiClient.api.getEmployeeData()
}
Employee.kt
data class Employee(
#SerializedName("id")
var employee_id: Int,
#SerializedName("employee_name")
var employee_name: String,
#SerializedName("employee_age")
var employee_age: Int,
#SerializedName("employee_salary")
var employee_salary: Int
)
Constants.kt
class Constants {
companion object{
const val BASE_URL = "http://dummy.restapiexample.com"
}
Error image
How can i solve this? please help me. Thank you
Retrofit only supports suspend keyword since 2.6.4, so using 2.3.0 won't work.
You should update to a newer version of Retrofit. The current latest version at the time of writing is 2.9.0.

Retrofit insert to room repository but only insert one row

I think is right but always insert one row, I don't know why? I'm user MVVM, dependency injection (Kodein), and Coroutin
(interface)
MyApi.kt
#GET("param-list-all")
suspend fun getParamterALL() : Response<List<AllParam>>
(class)
Provinsi.kt
#Entity(primaryKeys = ["id"])
data class Provinsi(
val createdBy: String?,
val createdDate: Long?,
val id: Int?,
val provinceCode: String?,
val provinceName: String?,
val updatedBy: String?,
val updatedDate: Long?
)
ProvinsiRepo.kt
class ProvinsiRepo(
private val api: MyApi,
private val db: AppDatabase
) : SafeApiRequest(){
suspend fun getAllProvinsiAPI(): List<Provinsi> {
return apiRequest{
api.getProvinsi()
}
}
suspend fun saveallParam(param: List<Provinsi>) = db.getProvinsiDao().upsert(param)
}
ProvinsiViewModel.kt
class ProvinsiViewModel(
private val provinsirepo: ProvinsiRepo,
) : ViewModel() {
provinsirepo.getAllProvinsiAPI().let { provinsi->
provinsirepo.saveallParam(provinsi)
}
DAO
#Dao
interface AllParamDAO {
#Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun upsert(parameter: List<AllParam>)
}
It might happen if the List returned by the API request always has the same id in the Provinsi object. If it is the same, then it will replace data in the DB because id is the primary key and it will maintain the UNIQUE constraint.
To fix this, you can try:
#Entity
data class Provinsi(
val createdBy: String?,
val createdDate: Long?,
#PrimaryKey(autoGenerate = true) val id: Int = 0, // use this line
val provinceCode: String?,
val provinceName: String?,
val updatedBy: String?,
val updatedDate: Long?
)

Kotlin - Parcelable Type mismatch: Required: String, Found: String?

The compiler is giving me the error Type mismatch: Required: String, Found: String? for the lines
parcel.writeString(firstName) and parcel.writeString(lastName) inside the constructor of a Parcelable data class.
Here is my class.
data class Mouse(
val firstName: String,
val lastName: String,
val age: Int ) : Parcelable {
constructor(parcel: Parcel) : this(
parcel.readString(),
parcel.readString(),
parcel.readInt()
)
override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeString(firstName)
parcel.writeString(lastName)
parcel.writeInt(age)
}
override fun describeContents(): Int {
return 0
}
companion object CREATOR : Parcelable.Creator<Mouse> {
override fun createFromParcel(parcel: Parcel): Mouse {
return Mouse(parcel)
}
override fun newArray(size: Int): Array<Mouse?> {
return arrayOfNulls(size)
}
}}
I don't understand why there is the error and how to correct it.
Actually, your error is caused by other lines. parcel.readString() returns String?, and you try to pass it to your primary constructor as firstName parameter which has String type. To fix it, you can, for example, pass a default value if returned string is null:
constructor(parcel: Parcel) : this(
parcel.readString() ?: "",
parcel.readString() ?: "",
parcel.readInt()
)

Kotlin Coroutines, retrofit-2.6.1, Network response null

I am going through reso-coder Weather app tutorial. Most of the things changed with the passage of time, so is apixu weather website.
Now it's the time of Retrofit 2.6.1 which means kotlin coroutines
The problem is that i am getting everything Null in network Response
I have go through all data classes with SerializedName, everything seems pretty fine, still can't get the problem..
BTW i'm not using ViewModel right now just directly hoping into the fragment textView
interface ApixuWeatherApiService {
#GET("current")
suspend fun getCurrentWeather(
#Query("query") location: String,
#Query("lang") languageCode: String = "en"
): CurrentWeatherResponse
//to handle this above interface we need companion object
companion object WeatherAPis {
private val requestInterceptor = Interceptor { chain ->
val url = chain.request()
.url().newBuilder().addQueryParameter("access_key", API_KEY)
.build()
val request = chain.request().newBuilder().url(url).build()
chain.proceed(request)
}
private val okHTTPClient = OkHttpClient.Builder().addInterceptor(requestInterceptor).build()
private fun retroFit(): Retrofit = Retrofit
.Builder()
.client(okHTTPClient)
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build()
val weatherApi: ApixuWeatherApiService =
retroFit().create(ApixuWeatherApiService::class.java)
}
}
Fragment Class
class CurrentWeatherFragment : Fragment() {
private lateinit var viewModel: CurrentWeatherViewModel
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.current_weather_fragment, container, false)
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
viewModel = ViewModelProviders.of(this).get(CurrentWeatherViewModel::class.java)
CoroutineScope(IO).launch {
widCOntext()
}
}
private suspend fun widCOntext() {
val apiService = ApixuWeatherApiService.weatherApi
withContext(Main) {
val currentWeatherResponse =
withContext(IO) {
apiService.getCurrentWeather(
"London"
)
}
txtView.text = currentWeatherResponse.toString()
}
}
}
I have used plugin to convert JSON to kotlin file to get these
Four data classes
Current
data class Current(
#SerializedName("observation_time")
val observationTime: String,
val temperature: Int,
#SerializedName("weather_code")
val weatherCode: Int,
#SerializedName("weather_icons")
val weatherIcons: List<String>,
#SerializedName("weather_descriptions")
val weatherDescriptions: List<String>,
#SerializedName("wind_speed")
val windSpeed: Int,
#SerializedName("wind_degree")
val windDegree: Int,
#SerializedName("wind_dir")
val windDir: String,
val pressure: Int,
val precip: Int,
val humidity: Int,
val cloudcover: Int,
val feelslike: Int,
#SerializedName("uv_index")
val uvIndex: Int,
val visibility: Int,
#SerializedName("is_day")
val isDay: String
)
CurrentWeatherResponse
data class CurrentWeatherResponse(
val request: Request,
val location: Location,
val current: Current
)
Location
data class Location(
val name: String,
val country: String,
val region: String,
val lat: String,
val lon: String,
#SerializedName("timezone_id")
val timezoneId: String,
val localtime: String,
#SerializedName("localtime_epoch")
val localtimeEpoch: Int,
#SerializedName("utc_offset")
val utcOffset: String
)
Request
data class Request(
val type: String,
val query: String,
val language: String,
val unit: String
)
Issue Solved : I hope this gonna help someone
Here what i did
Whenever i stuck somewhere, i make new project and try to work on that specific thing.
Now what i did over here which i think resolved my problem.
I have used singleton pattern, I have made Singleton instance of ApiService Interface, before singleton it was showing response 200 but output was null as well and now just by making singleton it resolved my Problem and now i am getting desired output
Here is code:
object RetrofitRequest {
private val interceptor = Interceptor {chain ->
val url = chain.request()
.url()
.newBuilder()
.addQueryParameter("access_key/key", yourApiKey)
.build()
val request = chain.request().newBuilder().url(url).build()
return#Interceptor chain.proceed(request)
}
private val okHttpClient = OkHttpClient
.Builder()
.addInterceptor(interceptor)
.build()
#Volatile
private var instance : ApiService? = null
fun getInstance() : ApiService = instance ?: synchronized(this) {
instance ?: fullResponse().also {
instance = it
}
}
private fun retrofitBuild() : Retrofit =
Retrofit.Builder()
.client(okHttpClient)
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build()
private fun fullResponse(): ApiService {
return retrofitBuild().create(ApiService::class.java)
}
}
Specifically this is the part i am talking about
#Volatile
private var instance : ApiService? = null
fun getInstance() : ApiService = instance ?: synchronized(this) {
instance ?: fullResponse().also {
instance = it
}
}
Now what i think what is happening over here:
Before Singleton the response was successful but instance was not visible for other threads. That is why it was null. As i am using coroutines it might be running from different thread, after making the singleton #volatile which makes the singleton visible for all threads. When the program try to run from different thread and #Volatile has capability to access to all threads,which made program execute successfully without null

Resources