Dispatcher - ArrayIndexOutOfBoundsException - kotlin

When executing this function, the following error appears:
FATAL EXCEPTION: OkHttp Dispatcher
java.lang.ArrayIndexOutOfBoundsException: length=0; index=0
How to solve?
fun run(url: String) {
val client = OkHttpClient()
val request = Request.Builder()
.url(url)
.build()
client.newCall(request).enqueue(object : Callback {
override fun onFailure(call: Call, e: IOException) {
Log.i("Falha", e.toString())
}
override fun onResponse(call: Call, response: Response) {
val json= response.body?.string()
val jsonArray = JSONTokener(json).nextValue() as JSONArray
for (i in 0 until jsonArray.length()) {
val x = jsonArray.getJSONObject(i).getString("nomeParque")
val y = jsonArray.getJSONObject(i).getString("morada")
val lat = jsonArray.getJSONObject(i).getString("latitude").toDouble()
val lng = jsonArray.getJSONObject(i).getString("longitude").toDouble()
nome.set(i, x)
morada.set(i, y)
latitude.set(i, lat)
longitude.set(i, lng)
}
}
})
}

You just have to add -1 in jsonArray.length() in the for sentence.

Related

How to serialize with retrofit and kotlin

Iam trying to serialize a response into Session class with Retrofit and Kotlin but i have an error. I am using inheritance here and maybe that is the problem i don't know :
"java.lang.IllegalArgumentException: Unable to create call adapter for retrofit2.Response<com.mobile.myapplication.Session> "
open class BaseUser {
var id:Int=0
var correo:String=""
var nombre:String=""
var apellido:String=""
var direccion:String=""
var telefono:String=""
var imagen:String=""
}
class Permiso {
var id:Int=0
var aplicacionId:Int=0
var aplicacionName:String=""
var lectura:Boolean=false
var escritura:Boolean=false
}
class Session: BaseUser() {
var token:String=""
var permiso:List<Permiso> = emptyList()
}
class LocalViewModel(private val retro:Retro= Retro()):ViewModel(){
private val _result = MutableStateFlow("")
val result:StateFlow<String> = _result
init {
viewModelScope.launch {
val jsonObject= JSONObject()
jsonObject.put("correo", "xxxxxx.com")
jsonObject.put("password", "xxxxx")
Log.d("payload",jsonObject.toString())
retro.token(jsonObject.toString())
}
}
}
#Composable
fun main(vm: LocalViewModel= viewModel()){
Text(text = "Hello world")
}
interface APIService {
#POST("api/Auth/SignIn")
fun requestToken(#Body requestBody: RequestBody): Response<Session>
}
class Retro{
fun getinstance(): APIService? {
var service:APIService?=null
try {
// Create Retrofit
val retrofit = Retrofit.Builder()
.baseUrl("xxxxxxxxx")
.addConverterFactory(GsonConverterFactory.create())
.build()
// Create Service
service = retrofit.create(APIService::class.java)
}catch (err:Error){
Log.e("RETROFIT_ERROR", err.toString())
}
return service
}
fun token(payload:String){
val instance=getinstance()
val requestBody = payload.toRequestBody("application/json".toMediaTypeOrNull())
val response = instance?.requestToken(requestBody)
Log.d("response",response.toString())
}
}
API response is like this :
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJOb21icmUiOiJSaWNoYXJkIiwiQXBlbGxpZG8iOiJWw61xdWV6IiwiQ29ycmVvIjoiUnZpcXVlekBzb2Zub21pYy5jb20iLCJEaXJlY2Npb24iOiJIZXJlZGlhIiwiVGVsZWZvbm8iOiJQw6lyZXoiLCJuYmYiOjE2NTc3MjQzOTksImV4cCI6MTY1Nzc0OTU5OSwiaXNzIjoiaHR0cHM6Ly9zb2Zub21pY2FwaS5henVyZXdlYnNpdGVzLm5ldC8ifQ.HtBEe1XlqyU0YBVyGJ1fs-EUiJn8vbWKqvNci2tOboU",
"id": 26,
"correo": "xxxxx.com",
"nombre": "xx",
"apellido": "xx",
"direccion": "xxx",
"telefono": "xx",
"imagen": null,
"permiso": []
}
What is the problem ???
I don't know why but with Response does not work only with Call instead Response!:
interface APIService {
#POST("api/Auth/SignIn")
fun requestToken(#Body requestBody: RequestBody): Call<Session>
}
fun token(payload:String):Session?{
val instance=getinstance()
val requestBody = payload.toRequestBody("application/json".toMediaTypeOrNull())
var session: Session?=null
val response = instance?.requestToken(requestBody) ?: return null
response.enqueue(object : Callback<Session?> {
override fun onResponse(call: Call<Session?>?, response: Response<Session?>) {
val statusCode = response.code()
if (statusCode!=200){
return
}
session = response.body()
}
override fun onFailure(call: Call<Session?>?, t: Throwable?) {
return
}
})
return session
}

WorkManager observe retrofit progress

I am uploading the file using Kotlin workmanager. In CoroutineWorkmanager, I do file upload with a suspend upload function. I want to observe retrofit progress and show it on ui. I can see the retrofit progress state but I cannot observe it in workManager.
My request body class where I can see the retrofit progress state :
class ProgressRequestBody : RequestBody {
val mFile: File
val ignoreFirstNumberOfWriteToCalls : Int
constructor(mFile: File) : super(){
this.mFile = mFile
ignoreFirstNumberOfWriteToCalls = 0
}
constructor(mFile: File, ignoreFirstNumberOfWriteToCalls : Int) : super(){
this.mFile = mFile
this.ignoreFirstNumberOfWriteToCalls = ignoreFirstNumberOfWriteToCalls
}
var numWriteToCalls = 0
private val _shared = MutableStateFlow<Float>(0F)
val shared : StateFlow<Float> = _shared
override fun contentType(): MediaType? {
return "image/*".toMediaTypeOrNull()
}
#Throws(IOException::class)
override fun contentLength(): Long {
return mFile.length()
}
#Throws(IOException::class)
override fun writeTo(sink: BufferedSink) {
numWriteToCalls++
val fileLength = mFile.length()
val buffer = ByteArray(DEFAULT_BUFFER_SIZE)
val `in` = FileInputStream(mFile)
var uploaded: Long = 0
try {
var read: Int
var lastProgressPercentUpdate = 0.0f
read = `in`.read(buffer)
while (read != -1) {
uploaded += read.toLong()
sink.write(buffer, 0, read)
read = `in`.read(buffer)
if (numWriteToCalls > ignoreFirstNumberOfWriteToCalls ) {
val progress = (uploaded.toFloat() / fileLength.toFloat()) * 100f
if (progress - lastProgressPercentUpdate > 1 || progress == 100f) {
_shared.value = progress
Log.d("progress", "${shared.value}")
lastProgressPercentUpdate = progress
}
}
}
} finally {
`in`.close()
}
}
companion object {
private val DEFAULT_BUFFER_SIZE = 2048
}
}
The worker I uploaded the file to:
class UploadWorker #WorkerInject constructor(
private val repository: Repository,
#Assisted context: Context,
#Assisted params: WorkerParameters
): CoroutineWorker(context, params) {
private lateinit var result: UploadResult
#ObsoleteCoroutinesApi
#OptIn(ExperimentalCoroutinesApi::class)
#SuppressLint("RestrictedApi")
override suspend fun doWork(): Result {
return try{
val requestBody = ProgressRequestBody(File(fileUri!!.toUri().path))
val multipartBody = prepareBody(fileUri!!.toUri(), photoPart)
progressState(requestBody)
upload(multipartBody)
Result.Success()
}catch(e :Exception){
Result.failure()
}
}
private fun prepareBody( ): MultipartBody.Part {
return MultipartBody.Part.createFormData("photo", "photo", "image/*")
}
suspend fun upload(
multipartBody: MultipartBody.Part,
) {
repository.uploadPhotos(
multipartBody
).collect{ result ->
if (result is Result.Success) {
this.result = result.data
}
}
}
private suspend fun progressState(photoPart: ProgressRequestBody) {
coroutineScope {
launch {
photoPart.shared.collect{
setProgress(workDataOf(PROGRESS to it))
}
}
}
}
}
While this way I can't run the worker. I am getting the following error from the worker:
java.util.concurrent.CancellationException: Task was cancelled.
at androidx.work.impl.utils.futures.AbstractFuture.cancellationExceptionWithCause(AbstractFuture.java:1184)
at androidx.work.impl.utils.futures.AbstractFuture.getDoneValue(AbstractFuture.java:514)

After calling retrofitCall.enqueue neither the OnFailed block is executing neither the OnResponse

When I click on the button, callRetrofit function begins execution, but the mycall.enqueue none of the onFailure or onResponse codeblocks are executing. There is nothing I can get from the logcat.
Here is my callRetrofit function:
private fun callRetrofit() {
val file = File(selectedFile.toString())
val filePrt = RequestBody.create(MediaType.parse("image/*"), file)
val MP2 = MultipartBody.Part.createFormData("Photo", "Tasveer", filePrt)
val retrofit = Retrofit.Builder()
.baseUrl("https://www.googleapis.com/")
.addConverterFactory(GsonConverterFactory.create())
.build()
val jsonPlaceholderApi = retrofit.create(Jinterface::class.java)
val mycall = jsonPlaceholderApi.uploadFile(authoo, MP2)
mycall.enqueue(object : Callback<RequestBody?> {
override fun onFailure(call: Call<RequestBody?>, t: Throwable) {
Log.e("dikkat", t.message.toString())
}
override fun onResponse(call: Call<RequestBody?>, response: Response<RequestBody?>) {
Toast.makeText(this#MainActivity, "Donne", Toast.LENGTH_SHORT).show()
textView.text = response.body().toString()
Log.e("ressponse", response.body().toString())
}
})
}
And here's the interface:
interface Jinterface {
#Multipart
#POST("/upload/drive/v3/files?uploadType=media")
fun uploadFile(
#Header("Authorization") authorization: String,
#Part() file: MultipartBody.Part
) : Call<RequestBody>
}

How can I add securityToken to this resultactivity?

D/OkHttp: {"code":60202,"message":"Token required"}
This is server error problem.
I want solve code in this resultactivity.
I already setting securityToken here, but how can I add securityToken to request()?
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
val securityToken = SaveSharedPreference.getUserInfo(this)
val result = IntentIntegrator.parseActivityResult(requestCode, resultCode, data)
Client.retrofitService.request(result.contents).enqueue(object : Callback<String?> {
override fun onFailure(call: Call<String?>, t: Throwable) {
}
override fun onResponse(
call: Call<String?>?,
response: Response<String?>?
) {
if (response?.isSuccessful == false) {
val er = Gson().fromJson(response.errorBody()?.charStream(), ErrorResponse::class.java)
Log.d(_tag, "${er.code}:${er.message}")
if (er.code == 60201 || er.code== 60202)
{
Toast.makeText(this#Qrcode, "토큰이 유효하지 않습니다.", Toast.LENGTH_SHORT).show()
} else if (securityToken !=null) {
Log.d(_tag, "status: ${response?.code()}. body: ${response?.body()}")
}
}
}
})
}
}```
You can add additional parameter in your request like:
interface RetrofitService {
#GET("/request")
request(#Query("parameter") parameter: String, #Header("Security-Token") securityToken: String): Call<String>
}
Or,
You can build an OkHttpClient for your Retrofit in creating RetrofitService:
RetrofitService :
interface RetrofitService {
#GET("/request")
request(#Query("parameter") parameter): Call<String>
}
Retrofit Builder:
val securityToken = "securityTokenString"
val okHttpClient = OkHttpClient.Builder()
.addInterceptor { chain ->
val request = chain.request()
val newRequestBuilder = request.newBuilder()
.header("Security-Token", securityToken)
chain.proceed(newRequestBuilder.build())
}
val retrofit = Retrofit.Builder()
.addConverterFactory(gsonConverterFactory)
.client(okHttpClient)
.baseUrl(BASE_URL)
.build()
val retrofitService = retrofit.create(RetrofitService::class.java)

Using Retrofit in Kotlin

I am trying to hit api using retrofit in kotlin
This is my DoinBackGround Method
private fun doinBackground() {
Utility.printMessage("in do in background.....")
try {
val hdr = HashMap<String, String>()
hdr.put("x-csrf-token", Utility.getToken(this.context!!))
val apiInterface = ApiCallRetrofit.getClient(this.mCrypt!!)!!.create(ApiInterface::class.java)
if (what.equals(0)) {
val body = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), getQuery(para))
print("header...")
call = apiInterface.hitApi(url, hdr, body)
} else if (what.equals(1)) {
val imgPart = ArrayList<MultipartBody.Part>()
if (files != null) {
if (files.size > 0) {
for (i in files.indices) {
imgPart.add(preparePart("image/*", "document_file[" + files.get(i).key + "]", files.get(i).file))
}
}
call = apiInterface.hitApiImage(url, hdr, getMap(para), imgPart)
}
call?.enqueue(object : Callback<StandardReposnse> {
override fun onResponse(call: Call<StandardReposnse>, response: Response<StandardReposnse>) {
try {
Utility.printMessage("messege...." + response.body().message)
val resp = Gson().toJson(response.body())
Utility.printMessage("Response :$resp")
Utility.longLogPrint(response.body().data, "Full response : ")
Utility.printMessage("Error : " + Gson().toJson(response.errorBody()))
onPostExecute(Parseresponce(response.body()))
} catch (e: Exception) {
Parseresponce(null)
e.printStackTrace()
}
}
override fun onFailure(call: Call<StandardReposnse>, t: Throwable) {
t.printStackTrace()
if (progressDialog != null) {
progressDialog?.dismiss()
}
Parseresponce(null)
}
})
}
} catch (e: Exception) {
e.printStackTrace()
}
}
And this is my interface where I am defining all the POST methods
#POST
abstract fun hitApi(#Url api: String, #HeaderMap header: Map<String, Any>, #Body body: RequestBody): Call<StandardReposnse>
#POST
fun hitApiNoHeader(#Url api: String, #Body requestBody: RequestBody): Call<StandardReposnse>
#POST
fun test(#Url api: String, #HeaderMap headerMap: Map<String, String>, #Body requestBody: RequestBody): Call<JSONObject>
#Multipart
#POST
fun hitApiImage(#Url api: String, #HeaderMap headerMap: Map<String, String>, #PartMap bodyMap: Map<String, RequestBody>, #Part images: List<MultipartBody.Part>): Call<StandardReposnse>
Whenever I am trying to hit the Api I am getting the following exception :
java.lang.IllegalArgumentException: Parameter type must not include a type variable or wildcard: java.util.Map<java.lang.String, ?> (parameter #2)
for method ApiInterface.hitApi
at retrofit2.ServiceMethod$Builder.methodError(ServiceMethod.java:720)
at retrofit2.ServiceMethod$Builder.methodError(ServiceMethod.java:711)
at retrofit2.ServiceMethod$Builder.parameterError(ServiceMethod.java:729)
at retrofit2.ServiceMethod$Builder.build(ServiceMethod.java:193)
at retrofit2.Retrofit.loadServiceMethod(Retrofit.java:166)
This is the line where the exception occurs in doinbackground method
call = apiInterface.hitApi(url, hdr, body)
I tried #JvmSuppressWildcards before the RequestBody but it did not work, can anyone suggest whats the actual problem over here, plus nothing is printing in the log though I have used print() function should i use LOG.d?
Here i have fully example for it.
This dependancy add in gradle
implementation 'com.squareup.retrofit2:retrofit:2.5.0'
annotationProcessor 'com.squareup.retrofit2:retrofit:2.5.0'
implementation 'com.squareup.retrofit2:converter-gson:2.4.0'
Here now create ApiClient.kt file
object ApiClient {
val BASE_URL = "http://yourwebsite/services/"
private var retrofit: Retrofit? = null
val client: Retrofit
get() {
if (retrofit == null) {
retrofit = Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build()
}
return retrofit!!
}
}
Now create APIInterface.kt
#FormUrlEncoded
#POST("users/login")
fun POST_LOGIN(
#Field("imei_number") imei_number: String,
#Field("device_token") device_token: String,
#Field("mobile") mobile: String,
#Field("password") password: String
): Call<LoginResponse>
#GET("general/init-data")
fun GENERAL_MODULE(
#Header("Authorization") auth_key: String
): Call<InitResponse>
#GET("event-gallery/list")
fun GET_Event_GALLERY(
#Header("Authorization") auth_key: String
): Call<EventListResponse>
#GET("event-gallery/photo-list")
fun GET_Event_GALLERY_PHOTO(
#Header("Authorization") auth_key: String,
#Query("id") id: Int
): Call<EventGallerListResponse>
if Any Header for token the use #Header and also When call #GET that time params use #Query and #Post that time #Fields
Now Response file
data class EventListResponse(
#SerializedName("success")
var success: Boolean,
#SerializedName("data")
var data: EventgalleryModel?,
#SerializedName("server_error"),
#SerializedName("eventgallery")
var eventgallery: ArrayList<EventListData>
var server_error: Boolean,
#SerializedName("message")
var message: String
)
Then create Model class of Response
Now time to Activity code
private fun loadData() {
card_progress.visibility = View.VISIBLE
val apiService = ApiClient.client.create(ApiInterface::class.java)
val call =
apiService.GET_FEE_INSTALMENT_LIST(PreferenceManager.getAuthKey(this#FeesInstalmentActivity)!!)
call.enqueue(object : Callback<FeeInstalmentListResponse> {
override fun onResponse(
call: Call<FeeInstalmentListResponse>,
response: Response<FeeInstalmentListResponse>
) {
card_progress.visibility = View.GONE
val data = response.body()!!.data
if (response.code() == 200 && data != null) {
if (response.body()!!.server_error) {
txt_no_data_fee.visibility = View.VISIBLE
txt_no_data_fee.text = response.body()!!.message
} else {
Log.e("data", data.toString())
if (data != null && data.feesinstalment.isEmpty()) {
txt_no_data_fee.visibility = View.VISIBLE
} else {
txt_no_data_fee.visibility = View.GONE
adapter!!.setItem(data.feesinstalment)
}
}
} else if (response.code() == 401) {
PreferenceManager.removePref(this#FeesInstalmentActivity)
startActivity(
Intent(this#FeesInstalmentActivity, LoginActivity::class.java)
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK)
)
finish()
} else {
Toast.makeText(
this#FeesInstalmentActivity,
R.string.somethingWrong,
Toast.LENGTH_SHORT
).show()
}
}
override fun onFailure(call: Call<FeeInstalmentListResponse>, t: Throwable) {
card_progress.visibility = View.GONE
Log.e("onFailure", t.message)
txt_no_data_fee.visibility = View.VISIBLE
}
})
}
Adapter
class FeeInstalmentAdapter(
private val context: Context,
private var items: ArrayList<FeeInstalmentListData>
) : RecyclerView.Adapter() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
return ViewHolder(LayoutInflater.from(context).inflate(R.layout.row_fees_instalment_item, parent, false))
}
#SuppressLint("SetTextI18n")
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.due_date.text = DateHelper.parseData(items[position].due_date!!, "yyyy-MM-dd", "dd MMM yyyy")
holder.instalment_title.text = items[position].instalment_title
if (items[position].paid_date == null) {
holder.paid_text.visibility = View.GONE
holder.paid_date.text = context.resources.getString(R.string.UnPaid)
holder.paid_date.setTextColor(Color.parseColor("#DC143C"))
} else {
holder.paid_date.text = DateHelper.parseData(items[position].due_date!!, "yyyy-MM-dd", "dd MMM yyyy")
holder.paid_date.setTextColor(Color.parseColor("#58A259"))
}
//holder.paid_date.text = items[position].paid_date
holder.amount.text = "Rs. " + items[position].amount
holder.amount.setTextColor(Color.parseColor("#ED7136"))
}
override fun getItemCount(): Int {
return items.size
}
override fun getItemId(position: Int): Long {
return position.toLong()
}
override fun getItemViewType(position: Int): Int {
return position
}
fun setItem(holidays: ArrayList<FeeInstalmentListData>) {
items = holidays
notifyDataSetChanged()
}
class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
val due_date = view.due_date
val instalment_title = view.instalment_title
val paid_date = view.paid_date
val amount = view.amount
val paid_text = view.paidText
}
}
You have used:
#POST
abstract fun hitApi(#Url api: String, #HeaderMap header: Map<String, Any>, #Body body: RequestBody): Call<StandardReposnse>
And exception is:
Parameter type must not include a type variable or wildcard: java.util.Map<java.lang.String, ?> (parameter #2)
And your hitApi #2 param use wildcard actually:
#HeaderMap header: Map<String, ?>
Try to specify argument (just change Any to String). Anyway you are not probably going to put Any object than String in your request header.
Call it in the below mentioned way.
val callWeather = NetworkUtils.getApiInterface().getWeatherResponse("03a7949903004a0bb2590633181104", "1.909,45.909", 7)
callWeather.enqueue(object : Callback<APIXUResponse> {
override fun onResponse(call: Call<APIXUResponse>, response: Response<APIXUResponse>) {
var api :APIXUResponse? = response.body()
}
override fun onFailure(call: Call<APIXUResponse>, t: Throwable) {
}
})