androidclojurekotlincompojurehttp-kit

Retrofit failing to post on samsung s3 android version 4.0.4 while on data


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
   )

Solution

  • 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.