AndroidNetworking.upload() is giving bad request in every case.
Testing API on postman which is working fine, but unable to create the same request in AndroidNetworking, any help would be appreciated
Tried AndroidNetworking.post() method which gives a proper response from the server (asking to send file) but in that request unable to add a multipart file, which is required from for server to process.
var request = Rx2AndroidNetworking.upload(ApiEndPoint.SUBMIT_KYC_DOCUMENT)
request.setContentType("multipart/form-data")
request.addMultipartParameter ("json","{\"POADocumentType\":40, \"POIDocumentType\":60,\"ReSubmitDocument\":false}","text/plain")
try {
if (selfie.docFront != null) {
request.addMultipartFile("Selfie", selfie.docFront,"multipart/form-data")
}
} catch (unInitialsied: UninitializedPropertyAccessException) {
}
return request.build()
.setUploadProgressListener(object : UploadProgressListener {
override fun onProgress(bytesUploaded: Long, totalBytes: Long) {
Log.d("", "")
}
})
.getAsJSONObject(object : JSONObjectRequestListener {
override fun onResponse(response: JSONObject?) {
Log.d("", "")
}
override fun onError(anError: ANError?) {
Log.d("", "")
}
})
By the way, it's working in postman
https://ibb.co/3W4qKR6
I dont know how this android networking library works in kotlin but my issue got resolved when I commented
AndroidNetworking.enableLogging();
All my multipart call in this library works fine,after commenting it.
Related
I'm trying to make a GET request to my server from my Android application using Retrofit, OKHttp, and Kotlin Flow w/ MVVM architecture.
For some reason whenever I try to invoke my GET request from a try-catch scope the program always enters catch, but the value of Throwable is always null. It's as if there was a crash but no exception being thrown for me to examine in the logs/debugger.
Filtering logcat for OKHTTP logs I can see that the network request never occurs/reaches the server. It seems to be failing locally, somewhere in my device's app process, before triggering the catch block.
Other network calls execute fine in this same project, so something about my specific implementation for this one must be incorrect. What am I missing?
RemoteDataSource.kt
suspend fun getProductData(skuId: String): Result<ProductLookupResponse>{
return getResponse(
request = {
pickingAPI.lookupProductBySku(
"Test User",
"A place",
skuId
)
},
defaultErrorMessage = "Error looking up product"
)
}
private suspend fun <T> getResponse(
request: suspend () -> Response<T>,
defaultErrorMessage: String
): Result<T> {
return try {
val result = request.invoke() //Always Crashes here for this request
if (result.isSuccessful) {
Result.success(result.body())
} else {
val networkError = NetworkError(code = result.code(), message = result.message())
Result.error(message = networkError.message ?: "", error = networkError)
}
} catch (e: Exception) {
Result.error(defaultErrorMessage, null)
}
}
Repo.kt
suspend fun getProductData(
skuId: String
): Flow<Result<ProductLookupResponse>> {
return flow {
emit(Result.loading())
emit(RemoteDataSource.getProductData(skuId))
}.flowOn(Dispatchers.IO)
}
API.kt
#GET("garments/sku/{skuId}")
fun lookupProductBySku(
#Header(HEADER_ASSOCIATE_ID) userUniqueId: String,
#Header(HEADER_LOCATION_ID) dcId: String,
#Path("skuId") sku: String
): Response<ProductLookupResponse>
I've spent hours trying to figure this thing out, and I still can figure it out.
I'm trying to retrieve data from a website using JSON.
If the website is live and everything, it works, but if the website returns something else than the data, like a 403 error, or any other error, then it crashes. I tried to debug it, but I still don't understand what is going on here.
Here is my code:
I have a NetworkModule with an interceptor that is supposed to check is the response is valid or not, and from what I can tell it works, because my variable isDataRetrievable is false (the value by default):
val networkModule = module {
single {
val customGson =
GsonBuilder().registerTypeAdapter(Lesson::class.java, LessonDeserializer())
.create()
Retrofit.Builder()
.client(get())
.addConverterFactory(
GsonConverterFactory.create(customGson)
)
.baseUrl(BuildConfig.URL)
.build()
}
factory {
OkHttpClient.Builder()
.addInterceptor(Interceptor { chain ->
chain.withConnectTimeout(1,TimeUnit.SECONDS)
val request: Request = chain.request()
val response = chain.proceed(request)
if (response.isSuccessful){
networkStatus.isDataRetrievable = true
}
response
}).build()
}
factory {
get<Retrofit>().create(LessonApi::class.java)
}
}
Next, I have my API to get the data:
interface LessonApi {
#GET("/JSON/json_get_data.php")
suspend fun getLessons(): Call<Lesson>
}
Then, for some reason, I have a repository (I'm not the only one working on this code, I didn't do this part):
class LessonRepository(private val service: LessonApi) {
suspend fun getLessons() = service.getLessons()
}
Then, I have my splash screen view model, that is supposed to retrieve the data if possible:
if (networkStatus.isNetworkConnected && networkStatus.isWebsiteReachable) {
var tmp = repository.getLessons()
tmp.enqueue(object : Callback<Lesson> {
override fun onFailure(call: Call<Lesson>, t: Throwable) {
Log.d("DataFailure",t.message.toString())
nextScreenLiveData.postValue(false)
}
override fun onResponse(call: Call<Lesson>, response: Response<Lesson>) {
Log.d("DataFailure","Test")
}
})
}else{
nextScreenLiveData.postValue(false)
}
The problem is that when the program get to the line repository.getLessons(), it crashes with the error:
retrofit2.HttpException: HTTP 403
at retrofit2.KotlinExtensions$await$2$2.onResponse(KotlinExtensions.kt:49)
at retrofit2.OkHttpCall$1.onResponse(OkHttpCall.java:129)
at okhttp3.internal.connection.RealCall$AsyncCall.run(RealCall.kt:519)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:919)
So onFailure or onResponse are never called. I tried to run the debugger, to step in, but I cannot figure it out when it fails.
I thought it was because it was trying to deserialize invalid data, but I put breakpoints everywhere in my deserializer, and it never hits the breakpoints.
I'm not a professional android developer, but I'm very confused here.
What I'd like to do is that if the request is unsuccessful, just discard the response (do not deserialize it), and display a message or exit.
Please help, it's so frustrating. I'm not sure how to intercept errors or what to do if Interceptors get an unsuccessful request (for now I just set a variable but it's unused).
Thanks.
Edit: What I'm trying to do, is to retrieve data from a webserver. If it cannot (for any reason), I don't want the gson to parse data (because it will probably be garbage and will not correspond to my deserializer). However, I feel like this okhttp / retrofit is a pipeline, where okhttp get the response from the webserver and pass it to a gson converter. What I want to do is intercept this response, and if it's not successful, to NOT pass it to gson, set a variable, so that the rest of my application knows what to do. But the thing is, for now, it just crash even before it gets to the callback in enqueue. The interceptor works just fine, except I'd like him to drop the response if it's not successful. Is it possible?
I tried something like that, and it worked to handle bad codes (>400), but I also wanted to handle malformed JSON data, so I added the onResponse and onFailure callbacks, but it never worked, because when I receive a malformed JSON, it also trigger an exception, and then go in the catch before it can go on the 'enqueue', so I'm not sure what this is used for.
try {
val lessons = repository.getLessons().enqueue(object : Callback<List<Lesson>> {
override fun onResponse(call: Call<List<Lesson>>, response: Response<List<Lesson>>) {
networkStatus.isDataRetrievable = response.isSuccessful
Log.d("Retrofit", "Successful response")
nextScreenLiveData.postValue(response.isSuccessful)
}
override fun onFailure(call: Call<List<Lesson>>, t: Throwable) {
Log.d("Retrofit", "Failure response")
nextScreenLiveData.postValue(false)
}
})
nextScreenLiveData.postValue(true)
} catch (e: Exception) {
nextScreenLiveData.postValue(false)
}
Anyway, just this code works for everything in the end:
try {
val lessons = repository.getLessons().filter {
it.lesson.contains("video")
}.filter {
DataUtils.isANumber(it.id)
}
lessonDao.insertLessons(lessons)
networkStatus.isDataRetrievable = true
} catch (e: Exception) {
networkStatus.isDataRetrievable = false
}
But in my API, I don't return callbacks, I directly return the objects, as such:
#GET("/JSON/json_get_dat.php")
suspend fun getLessons(): List<Lesson>
I don't know if this is the right way to do it, but it works. I hope this might help others.
I am new to Android development with Kotlin and I am struggling on finding any useful documentation on how to create a simple GET and POST requests with the best current practices as possible. I am coming from an Angular development and there we used a reactive development using RxJS.
Normally I would create a service file that would hold all my request functions, then I would use this service in whichever component and subscribe to the observable.
How would you do this in Android? Is there a good started example of things that have to be created. From the first look, everything looks so complicated and over-engineered
I suggest you to use the official recommendation of OkHttp, or the Fuel library for easier side and it also has bindings for deserialization of response into objects using popular Json / ProtoBuf libraries.
Fuel example:
// Coroutines way:
// both are equivalent
val (request, response, result) = Fuel.get("https://httpbin.org/ip").awaitStringResponseResult()
val (request, response, result) = "https://httpbin.org/ip".httpGet().awaitStringResponseResult()
// process the response further:
result.fold(
{ data -> println(data) /* "{"origin":"127.0.0.1"}" */ },
{ error -> println("An error of type ${error.exception} happened: ${error.message}") }
)
// Or coroutines way + no callback style:
try {
println(Fuel.get("https://httpbin.org/ip").awaitString()) // "{"origin":"127.0.0.1"}"
} catch(exception: Exception) {
println("A network request exception was thrown: ${exception.message}")
}
// Or non-coroutine way / callback style:
val httpAsync = "https://httpbin.org/get"
.httpGet()
.responseString { request, response, result ->
when (result) {
is Result.Failure -> {
val ex = result.getException()
println(ex)
}
is Result.Success -> {
val data = result.get()
println(data)
}
}
}
httpAsync.join()
OkHttp example:
val request = Request.Builder()
.url("http://publicobject.com/helloworld.txt")
.build()
// Coroutines not supported directly, use the basic Callback way:
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())
}
}
})
you can use something like that:
internal inner class RequestTask : AsyncTask<String?, String?, String?>() {
override fun doInBackground(vararg params: String?): String? {
val httpclient: HttpClient = DefaultHttpClient()
val response: HttpResponse
var responseString: String? = null
try {
response = httpclient.execute(HttpGet(uri[0]))
val statusLine = response.statusLine
if (statusLine.statusCode == HttpStatus.SC_OK) {
val out = ByteArrayOutputStream()
response.entity.writeTo(out)
responseString = out.toString()
out.close()
} else {
//Closes the connection.
response.entity.content.close()
throw IOException(statusLine.reasonPhrase)
}
} catch (e: ClientProtocolException) {
//TODO Handle problems..
} catch (e: IOException) {
//TODO Handle problems..
}
return responseString
}
override fun onPostExecute(result: String?) {
super.onPostExecute(result)
//Do anything with response..
}
}
and for call:
RequestTask().execute("https://v6.exchangerate-api.com/v6/")
HttpClient is not supported any more in sdk 23. You have to use URLConnection or downgrade to sdk 22 (compile 'com.android.support:appcompat-v7:22.2.0')
If you need sdk 23, add this to your gradle:
android {
useLibrary 'org.apache.http.legacy'
}
You also may try to download and include HttpClient.jar directly into your project or use OkHttp instead
The best practice you ever get to just go through the basics of networking call and create some demo applications using Android Studio.
If you want to click start then follow this tutorial
Simplet netwroking call in Kotlin
https://www.androidhire.com/retrofit-tutorial-in-kotlin/
Also, I would like to suggest Please create some demo application for GET and POST request and then merge these examples into your project.
I am using Pusher Beams for sending notification to my users. It worked fine but today I got this error, and I don't know how to solve it.
PushNotificationsAPI: Failed to register device: NOKResponse(error=Unauthorized, description=The device token provided could not be validated against any known credentials)
This is my code:
private fun setPusherBeam() {
try {
val tokenProvider = BeamsTokenProvider(
BuildConfig.PUSHER_BEAM,
object : AuthDataGetter {
override fun getAuthData(): AuthData {
return AuthData(
headers = hashMapOf(
"Authorization" to getHawkString(AUTH_TOKEN)
),
queryParams = hashMapOf()
)
}
}
)
PushNotifications.setUserId(
DbHelper.getUser()?.user_id.toString(),
tokenProvider,
object : BeamsCallback<Void, PusherCallbackError> {
override fun onFailure(error: PusherCallbackError) {
Timber.i("BeamsAuth Could not login to Beams: ${error.message}")
}
override fun onSuccess(vararg values: Void) {
Timber.i("BeamsAuth Beams login success $values")
}
}
)
} catch (ex: Exception) {
Timber.i("BeamsAuth ex ${ex.localizedMessage}")
}
}
After 2days of struggling with this error, finally, it resolved due to these steps.
1-stop the API
PushNotifications.start(applicationContext, BuildConfig.INSTANCE_ID)
PushNotifications.stop()
PushNotifications.removeDeviceInterest("example")
PushNotifications.clearDeviceInterests()
2-clear android studio cash and reset it
3-remove the app from mobile and reinstall it
4-replace code from step1 with this
PushNotifications.start(applicationContext, BuildConfig.INSTANCE_ID)
PushNotifications.addDeviceInterest("example")
5-repeat 2 and 3
Delete the generated values.xml under app\build\generated\res\google-services\debug\values, then delete the app and build again. Took me a while to figure this out.
I'm trying to learn to code android apps with kotlin. I want to display some data that i get from the api(https://api.kuroganehammer.com/api/characters). I generated the data classes using the JSON to kotlin plugin in IntelliJ.
Logcat shows that i'm getting the Data however it doesn't trigger the onResponse method.
I tried debugging but can't really find anything other than for some reason the onFailure and onResponse methods are ignored.
ApiRequest:
fun fetchAllCharacters(): Call<CharacterApiRequest>
CharacterApiRequest:
#SerializedName("character")
val characters: List<Character>
)
Characters(Fragment, gets called in onViewCreated()):
.enqueue(object : Callback<CharacterApiRequest> {
override fun onFailure(call: Call<CharacterApiRequest>, t: Throwable) {
//Display an error to the user, because there was a io exception
}
override fun onResponse(call: Call<CharacterApiRequest>, response: Response<CharacterApiRequest>) {
//We got a response
if (response.isSuccessful) {
//Bind the data only when we have it
response.body()?.apply {
adapter.setData(this.characters as MutableList<Character>)
}
} else {
//Display an error
}
}
})
Changing the callback's generic parameter from CharacterApiRequest to List worked, as stated in the comment from #MateuszHerych