I have an android app that works well on other android devices but it fails on samsung s3 running android version 4.0.4 on data. Retrofit throws 404 (page not found error) but the page exists and if I make the same request on wifi it works well. Anyone with an idea on what could be misbehaving. Thanks
Please find below the stack trace
retrofit.RetrofitError: 404 Not Found
at retrofit.RestAdapter$RestHandler.invokeRequest (RestAdapter.java:388)
at retrofit.RestAdapter$RestHandler.access$100 (RestAdapter.java:220)
at retrofit.RestAdapter$RestHandler$2.obtainResponse (RestAdapter.java:278)
at retrofit.CallbackRunnable.run (CallbackRunnable.java:42)
at java.util.concurrent.ThreadPoolExecutor.runWorker (ThreadPoolExecutor.java:1076)
at java.util.concurrent.ThreadPoolExecutor$Worker.run (ThreadPoolExecutor.java:569)
at retrofit.Platform$Android$2$1.run (Platform.java:142)
at java.lang.Thread.run (Thread.java:856)
Below is the code I am using to make the call
val tailorsInterface = RestAdapter.Builder()
.setEndpoint(resources.getString(R.string.base_url))
.build().create(TailorsInterface::class.java)
tailorsInterface.addTailor(txtName.text.toString(), txtEmail.text.toString(),
Utils.parsePhone(txtPhone.text.toString(), "254"), txtAddress.text.toString(),
txtLon.text.toString(), txtLat.text.toString(), txtPassword.text.toString(),
Common.LOCATIONS!!.get(spTowns.selectedItemPosition).id, object : Callback<DefaultResponse> {
override fun success(defaultResponse: DefaultResponse, response: Response) {
dialog.hide()
if(defaultResponse.success == 1.toLong()){
val alertDialog: AlertDialog
val builder = AlertDialog.Builder(this@TailorsRegisterActivity)
.setTitle(resources.getString(R.string.app_name))
.setMessage("Tailor successfully registered, click OK to continue to login")
.setPositiveButton("OK") { dialog, which -> run{dialog.dismiss()
val loginIntent: Intent = Intent(this@TailorsRegisterActivity, TailorsLoginActivity::class.java)
startActivity(loginIntent)
} }
alertDialog = builder.create()
alertDialog.show()
}else{
val alertDialog: AlertDialog
val builder = AlertDialog.Builder(this@TailorsRegisterActivity)
.setTitle(resources.getString(R.string.app_name))
.setMessage("An Error occurred please try again later")
.setPositiveButton("OK") { dialog, which -> run{dialog.dismiss()
finish()} }
alertDialog = builder.create()
alertDialog.show()
}
}
@FormUrlEncoded
@POST("/tailors")
public fun addTailor(@Field("name") name: String, @Field("email") email: String,
@Field("phone") phone: String, @Field("address") address: String,
@Field("lon") lon: String, @Field("lat") lat: String,
@Field("password") password: String, @Field("town") town: Int,
cb: Callback<DefaultResponse>)
data class DefaultResponse (
var success: Long,
var message: String
)
After many days of debugging trying to figure out what the issue I finally found a solution the issue is not retrofit but it's the webserver I am using. I have my application done in clojure and I am using http-kit as my webserver and compojure for routing.
For some reason requests that are coming from s3 the uri in the http-kit request map also includes the host hence it's not being mapped to any route on my defroute. For example say if the route I am looking for is /login
the uri in the http-kit request map for the request coming from the s3 contains http://example.com/login
but from the other phones it contains /login
. Hence the uri doesn't match any of my routes I have defined in the compojure defroute and goes straight to not-found and hence the 404 error
The Solution
To solve this problem I had to extend Compojure routes.clj
and added the following function
(defn other-found
"if for some reason the route is defined and is not found "
[body]
(fn [request]
(-> (response/render body request)
(status 200)
(cond-> (= (:request-method request) :head) (assoc :body nil)))))
In defroute if the uri is not matched I use the function other-found
and pass it the the function not-found-page
(you can name this function whatever you want to call it) in the function I get the uri from the request parameter parse it and get the endpoint then use condp
to map the end point to the appropriate function.
Hope this helps someone with a similar problem.