How do I successfully make an okHttp request in Kotlin - android

Issues:
1. The request is not hitting my python flask server.
2. My app crashes whenever this code is run.
*Note: I have used Postman to test the localhost address, which is successful
I am trying to create an okHttp request in my kotlin android application.
I have implemented the needed dependencies in my build.gradle file:
implementation 'com.squareup.okhttp3:okhttp:3.10.0
edit: I included the Internet permission in the manifest file
<uses-permission android:name="android.permission.INTERNET" />
I have tried using my IP as part of the URL, along with a few different localhost links and have determined that the URL is not the issue.
If I am not mistaken, the app crash error occurs during build (), but I cannot wrap my mind around why.
Ideally, this code would hit the rest API and return data (printed as text)
on my login screen.
After a couple of days of researching and trying other request methods, I am unable to find a solution.
val mTextviewResult: TextView = findViewById(R.id.text_view_result)
//http client
var client = OkHttpClient()
val url = "http://localhost:5000/test"
val request = Request.Builder()
.url(url)
.build()
Log.d(request.toString(), ": I build Request")
client.newCall(request).enqueue(object : Callback {
override fun onFailure(call: Call, e: IOException) {
Log.d(url, ": I fail")
e.printStackTrace()
}
#Throws(IOException::class)
override fun onResponse(call: Call, response: Response) {
if (response.isSuccessful()) {
Log.d(url, ": I success")
val myResponse = response.body()?.string()
this#LoginActivity.runOnUiThread(object : Runnable {
override fun run() {
mTextviewResult.setText(myResponse)
}
})
}
}
})

To access localhost you should use local IPv4 + server PORT for localhost.
How to get this IPv4:
https://www.whatismybrowser.com/detect/what-is-my-local-ip-address
KOTLIN async request:
private val client = OkHttpClient()
fun run() {
val request = Request.Builder()
.url("http://IPv4_FROM_THE_LINK_ABOVE:5000/test")
.build()
client.newCall(request).enqueue(object : Callback {
override fun onFailure(call: Call, e: IOException) {
e.printStackTrace()
}
override fun onResponse(call: Call, response: Response) {
response.use {
if (!response.isSuccessful) throw IOException("Unexpected code $response")
for ((name, value) in response.headers) {
println("$name: $value")
}
println(response.body!!.string())
}
}
})
}
Install OkHttp: https://square.github.io/okhttp/

Related

Cannot make Post request in Retrofit Android (Kotlin)

I've been developing an Android Q&A app using Jetpack Compose. I've been trying to make Post requests in Retrofit but the data I send isn't on my API website. I've succeeded in making Get requests though. I've read many documents but I cannot find out what is wrong with this code.
This is data class.
data class UsersEntity(
val id: Int? = null,
val name: String? = null,
val uid: String? = null
)
This is Service interface.
interface UserService {
#POST("createusers")
fun createUsers(#Body usersinfo: UsersEntity): Call<Unit>
}
When I click a button, I'd like to send data to the server. I get the log "Hi, good job" but I cannot see the data on my API.
Button(
onClick = {
val moshi = Moshi.Builder()
.add(KotlinJsonAdapterFactory())
.build()
val retrofit = Retrofit.Builder()
.baseUrl("https://api.*****.com/")
.addConverterFactory(MoshiConverterFactory.create(moshi))
.build()
val service: UserService = retrofit.create(UserService::class.java)
val usersInfo = UsersEntity(
3, "Alex", "164E92FC-D37A")
service.createUsers(usersInfo).enqueue(object: Callback<Unit> {
override fun onResponse(call: Call<Unit>, response: Response<Unit>) {
Log.d("Hi", "good job")
}
override fun onFailure(call: Call<Unit>, t: Throwable) {
Log.d("Hi", "error")
}
})
}
I changed the code like this.
Button(
onClick = {
val moshi = Moshi.Builder()
.add(KotlinJsonAdapterFactory())
.build()
val retrofit = Retrofit.Builder()
.baseUrl("https://api.*****.com/")
.addConverterFactory(MoshiConverterFactory.create(moshi))
.build()
thread {
try {
val service: UserService = retrofit.create(UserService::class.java)
val usersInfo = UsersEntity(
3, "Alex", "164E92FC-D37A")
service.createUsers(usersInfo).enqueue(object: Callback<ResponseBody> {
override fun onResponse(call: Call<ResponseBody>, response: Response<ResponseBody>) {
Log.d("Response", "${response.body()}")
}
override fun onFailure(call: Call<ResponseBody>, t: Throwable) {
Log.d("Hi", "error")
}
})
} catch (e: Exception) {
Log.d("response", "debug $e")
}
}
},
Could someone help me? Thank you.
I think your baseurl shouldn't end with a slash. Try this.
.baseUrl("https://api.*****.com")
And for your interface (also the Call<ResponseBody>):
interface UserService {
#POST("/createusers/")
fun createUsers(#Body usersinfo: UsersEntity): Call<ResponseBody>
}
Got some issues with this in the past so this might help. If not it atleasts cleans the code a bit :p
Also you can use ProxyMan to intercept your request and read what your application is actually sending to the server, might be a issue to find there!
Proxyman.io

Using OkHttp3 to send requests in a specific order

I am working on an IoT project where I have an API that needs two HTTP requests to fetch a value (req1 to measure a distance, req2 to read the measured distance). I am trying to communicate with the APIs using Kotlin and OkHttp3, in the following manner:
1- Send req1 then req2
2- Make req2 return the measurement result to the main thread for further actions
However, sometimes the req2 seems to finish before req1, making the results unstable, also, req2 returns before the HTTP request finishes.
Req1 Function:
fun req1() {
val request = Request.Builder()
.url("https://IoT-API.com/Write")
.build()
client.newCall(request).enqueue(object : Callback {
override fun onFailure(call: okhttp3.Call, e: IOException) {
e.printStackTrace()
}
override fun onResponse(call: okhttp3.Call, response: okhttp3.Response) {
response.use {
if (!response.isSuccessful) throw IOException("Unexpected code $response")
}
}
})
}
Req2 Function:
fun req2(): String {
var distance = ""
val request = Request.Builder()
.url("https://IoT-API.com/Read")
.build()
client.newCall(request).enqueue(object : Callback {
override fun onFailure(call: okhttp3.Call, e: IOException) {
e.printStackTrace()
}
override fun onResponse(call: okhttp3.Call, response: okhttp3.Response) {
response.use {
if (!response.isSuccessful) throw IOException("Unexpected code $response")
val resp = response.peekBody(Long.MAX_VALUE).string()
val jsonObject = JSONTokener(resp).nextValue() as JSONObject
distance = jsonObject.getString("value")
}
}
})
return distance
}
Calling the functions:
checkButton.setOnClickListener {
req1()
var distance = req2()
resultTextView.text = "Distance: $distance"
}
I am aware that the cause of this issue is that HTTP requests are being performed on background threads, however, I am not sure how to solve this.

Android simulator - OkHttp (or Retrofit) callback not called

I'm creating an Android app. When using the simulator (Android v10) the callback of my OkHttp Get request is not called. (Same with Retrofit).
When I test on the real device it works fine.
Here is my code:
val url = "https://my.url/somewhere"
var client = OkHttpClient()
var request = Request.Builder().url(url).build()
client.newCall(request).enqueue( object: Callback {
override fun onFailure(call: Call, e: IOException) {
showErrorDialog()
}
override fun onResponse(call: Call, response: Response) {
debug("Got response")
moveToMainView(Gson().fromJson(response.body?.string(), Model.Data::class.java))
}
})
Any ideas why it would not work on the Simulator?

How to use OKHTTP to make a post request in Kotlin?

I need to make a post request to an endpoint from my android project. I am using Kotlin. Will I need to create a separate OKHttpClient Class for this.
Here's how you can achieve this:
val payload = "test payload"
val okHttpClient = OkHttpClient()
val requestBody = payload.toRequestBody()
val request = Request.Builder()
.method("POST", requestBody)
.url("url")
.build()
okHttpClient.newCall(request).enqueue(object : Callback {
override fun onFailure(call: Call, e: IOException) {
// Handle this
}
override fun onResponse(call: Call, response: Response) {
// Handle this
}
})
Don't forget to import:
import okhttp3.RequestBody.Companion.toRequestBody

Waiting for thread to complete OkHttp Call

I have been having problems with OkHttp when I nest an OkHttp call inside another OkHttp call I am having a problem with the concurrency. I want to wait for my inner call to finish its thread's job before proceeding. Please take a look.
Note: I am a novice with Kotlin and Multi-thread handling.
private fun parseJson(url: String) {
val request = Request.Builder()
.url(url)
.build()
client.newCall(request).enqueue(object : Callback {
override fun onResponse(call: Call, response: Response?) {
var bodyOfProducts = response?.body()?.string()
var collectionJsonObject = jsonParseTool.fromJson(bodyOfProducts, Products::class.java)
val productsWithDetails = ArrayList<ProductDetails>()
for(product in collectionJsonObject.collects){
var concatProductUrl = "https://shopicruit.myshopify.com/admin/products.json?ids=" + product.product_id+ "&page=1&access_token=c32313df0d0ef512ca64d5b336a0d7c6"
val newRequest = Request.Builder()
.url(concatProductUrl)
.build()
val job = thread {
client.newCall(newRequest).enqueue(object : Callback {
override fun onResponse(call: Call, newResponse: Response?) {
var bodyOfProductDetails = newResponse?.body()?.string()
var productJsonObject = jsonParseTool.fromJson(bodyOfProductDetails, ProductDetails::class.java)
productsWithDetails.add(productJsonObject)
}
override fun onFailure(call: Call, e: IOException) {
println("EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE")
}
})
}
job.start()
job.join() // This should force my thread to finish before the rest of the code is executed on the main thread.
}
// println(collectionJsonObject.collects[0].product_id)
/*runOnUiThread {
recyclerViewCustomCollections.adapter = CollectionsAdapter(jsonObject)
}*/
}
override fun onFailure(call: Call, e: IOException) {
println("EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE")
}
})
}
In this case you should be using execute as mentioned and since http calls are handled asynchronously your thread is redundant and should be removed.
If you want to run code after all the requests are finished one way of doing this is by passing in a onComplete callback function and count the number of requests completed, when all of the threads are completed call the callback function containing the code that should be run after all of the requests.

Categories

Resources