Retrofit insert to room repository but only insert one row - android-studio

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?
)

Related

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.

Post method using retrofit not working, logcat saying its null

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()
}
})
}

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

org.apache.spark.SparkException: Task not serializable, wh

When I implemented my own partioner and tried to shuffle the original rdd, I encounter a problem. I know this is caused by referring functions that are not Serializable, but, after adding
extends Serializable
to every relevent class, this problem still exists. What should I do?
Exception in thread "main" org.apache.spark.SparkException: Task not serializable
at org.apache.spark.util.ClosureCleaner$.ensureSerializable(ClosureCleaner.scala:166)
at org.apache.spark.util.ClosureCleaner$.clean(ClosureCleaner.scala:158)
at org.apache.spark.SparkContext.clean(SparkContext.scala:1622)
object STRPartitioner extends Serializable{
def apply(expectedParNum: Int,
sampleRate: Double,
originRdd: RDD[Vertex]): Unit= {
val bound = computeBound(originRdd)
val rdd = originRdd.mapPartitions(
iter => iter.map(row => {
val cp = row
(cp.coordinate, cp.copy())
}
)
)
val partitioner = new STRPartitioner(expectedParNum, sampleRate, bound, rdd)
val shuffled = new ShuffledRDD[Coordinate, Vertex, Vertex](rdd, partitioner)
shuffled.setSerializer(new KryoSerializer(new SparkConf(false)))
val result = shuffled.collect()
}
class STRPartitioner(expectedParNum: Int,
sampleRate: Double,
bound: MBR,
rdd: RDD[_ <: Product2[Coordinate, Vertex]])
extends Partitioner with Serializable {
...
}
I just solve the problem! add -Dsun.io.serialization.extendedDebugInfo=true to your VM config, you will target the unserializable class!

Resources