frankelot
frankelot

Reputation: 14409

Retrofit | Handle "server not found exception"

When trying to access a RESTful api from an android app, you want to check two things:

  1. That the User's wifi is enabled (and there's a established connection)
  2. Your app can actually reach the server. (my server is on a local network)

I've managed to check for the first one, but I have no idea how to check the latest.

Here's my output

05-25 15:49:46.929  15485-15999/com.tesis.restapp.restapp E/AndroidRuntime﹕ FATAL EXCEPTION: AsyncTask #1
    java.lang.RuntimeException: An error occured while executing doInBackground()
            at android.os.AsyncTask$3.done(AsyncTask.java:278)
            at java.util.concurrent.FutureTask$Sync.innerSetException(FutureTask.java:273)
            at java.util.concurrent.FutureTask.setException(FutureTask.java:124)
            at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:307)
            at java.util.concurrent.FutureTask.run(FutureTask.java:137)
            at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:208)
            at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1076)
            at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:569)
            at java.lang.Thread.run(Thread.java:856)
     Caused by: retrofit.RetrofitError: java.net.ConnectException: failed to connect to /192.168.1.25 (port 8080) after 15000ms: isConnected failed: ECONNREFUSED (Connection refused)
            at retrofit.RestAdapter$RestHandler.invokeRequest(RestAdapter.java:385)
            at retrofit.RestAdapter$RestHandler.invoke(RestAdapter.java:241)
            at $Proxy0.logIn(Native Method)
            at com.tesis.restapp.restapp.activities.intro.IntroActivity$SignIn.doInBackground(IntroActivity.java:83)
            at com.tesis.restapp.restapp.activities.intro.IntroActivity$SignIn.doInBackground(IntroActivity.java:70)
            at android.os.AsyncTask$2.call(AsyncTask.java:264)
            at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305)
            at java.util.concurrent.FutureTask.run(FutureTask.java:137)
            at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:208)
            at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1076)
            at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:569)
            at java.lang.Thread.run(Thread.java:856)
     Caused by: java.net.ConnectException: failed to connect to /192.168.1.25 (port 8080) after 15000ms: isConnected failed: ECONNREFUSED (Connection refused)
            at libcore.io.IoBridge.isConnected(IoBridge.java:220)
            at libcore.io.IoBridge.connectErrno(IoBridge.java:158)
            at libcore.io.IoBridge.connect(IoBridge.java:118)
            at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:192)
            at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:459)
            at java.net.Socket.connect(Socket.java:849)
            at libcore.net.http.HttpConnection.<init>(HttpConnection.java:77)
            at libcore.net.http.HttpConnection.<init>(HttpConnection.java:50)
            at libcore.net.http.HttpConnection$Address.connect(HttpConnection.java:351)
            at libcore.net.http.HttpConnectionPool.get(HttpConnectionPool.java:86)
            at libcore.net.http.HttpConnection.connect(HttpConnection.java:128)
            at libcore.net.http.HttpEngine.openSocketConnection(HttpEngine.java:308)
            at libcore.net.http.HttpEngine.connect(HttpEngine.java:303)
            at libcore.net.http.HttpEngine.sendSocketRequest(HttpEngine.java:282)
            at libcore.net.http.HttpEngine.sendRequest(HttpEngine.java:232)
            at libcore.net.http.HttpURLConnectionImpl.connect(HttpURLConnectionImpl.java:80)
            at libcore.net.http.HttpURLConnectionImpl.getOutputStream(HttpURLConnectionImpl.java:188)
            at retrofit.client.UrlConnectionClient.prepareRequest(UrlConnectionClient.java:66)
            at retrofit.client.UrlConnectionClient.execute(UrlConnectionClient.java:37)
            at retrofit.RestAdapter$RestHandler.invokeRequest(RestAdapter.java:322)
            at retrofit.RestAdapter$RestHandler.invoke(RestAdapter.java:241)
            at $Proxy0.logIn(Native Method)
            at com.tesis.restapp.restapp.activities.intro.IntroActivity$SignIn.doInBackground(IntroActivity.java:83)
            at com.tesis.restapp.restapp.activities.intro.IntroActivity$SignIn.doInBackground(IntroActivity.java:70)
            at android.os.AsyncTask$2.call(AsyncTask.java:264)
            at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305)
            at java.util.concurrent.FutureTask.run(FutureTask.java:137)
            at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:208)
            at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1076)
            at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:569)
            at java.lang.Thread.run(Thread.java:856)
     Caused by: libcore.io.ErrnoException: isConnected failed: ECONNREFUSED (Connection refused)
            at libcore.io.IoBridge.isConnected(IoBridge.java:207)
            at libcore.io.IoBridge.connectErrno(IoBridge.java:158)
            at libcore.io.IoBridge.connect(IoBridge.java:118)
            at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:192)
            at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:459)
            at java.net.Socket.connect(Socket.java:849)
            at libcore.net.http.HttpConnection.<init>(HttpConnection.java:77)
            at libcore.net.http.HttpConnection.<init>(HttpConnection.java:50)
            at libcore.net.http.HttpConnection$Address.connect(HttpConnection.java:351)
            at libcore.net.http.HttpConnectionPool.get(HttpConnectionPool.java:86)
            at libcore.net.http.HttpConnection.connect(HttpConnection.java:128)
            at libcore.net.http.HttpEngine.openSocketConnection(HttpEngine.java:308)
            at libcore.net.http.HttpEngine.connect(HttpEngine.java:303)
            at libcore.net.http.HttpEngine.sendSocketRequest(HttpEngine.java:282)
            at libcore.net.http.HttpEngine.sendRequest(HttpEngine.java:232)
            at libcore.net.http.HttpURLConnectionImpl.connect(HttpURLConnectionImpl.java:80)
            at libcore.net.http.HttpURLConnectionImpl.getOutputStream(HttpURLConnectionImpl.java:188)
            at retrofit.client.UrlConnectionClient.prepareRequest(UrlConnectionClient.java:66)
            at retrofit.client.UrlConnectionClient.execute(UrlConnectionClient.java:37)
            at retrofit.RestAdapter$RestHandler.invokeRequest(RestAdapter.java:322)
            at retrofit.RestAdapter$RestHandler.invoke(RestAdapter.java:241)
            at $Proxy0.logIn(Native Method)
            at com.tesis.restapp.restapp.activities.intro.IntroActivity$SignIn.doInBackground(IntroActivity.java:83)
            at com.tesis.restapp.restapp.activities.intro.IntroActivity$SignIn.doInBackground(IntroActivity.java:70)
            at android.os.AsyncTask$2.call(AsyncTask.java:264)
            at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305)
            at java.util.concurrent.FutureTask.run(FutureTask.java:137)
            at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:208)
            at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1076)
            at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:569)
            at java.lang.Thread.run(Thread.java:856)

EDIT

Here's my interface (for now, it just tries to log a user in)

public interface RestAppApiInterface {

    @FormUrlEncoded
    @POST(Constants.URL_LOGIN)
    public User logIn(@Field("username") String username, @Field("password") String password);

}

This class returns an instance of the interface:

public class ApiClient {

    private static final String API_URL = "http://192.168.1.25:8080";

    private static RestAppApiInterface sRestAppService;

    public static RestAppApiInterface getRestAppApiClient() {
        if (sRestAppService == null) {
            RestAdapter restAdapter = new RestAdapter.Builder()
                    .setEndpoint(API_URL)
                    .build();
            sRestAppService = restAdapter.create(RestAppApiInterface.class);
        }
        return sRestAppService;
    }

}

I call the service within a AsynTask like this

RestAppApiInterface apiInterface = ApiClient.getRestAppApiClient();
apiInterface.logIn("username","p@55w0rd");

Upvotes: 1

Views: 3960

Answers (3)

Malak Pete
Malak Pete

Reputation: 1

If you can you may use async call. Exceptions in Retrofit are better handled if you use async call. Asynchronous execution requires the last parameter of the method be a Callback. (http://square.github.io/retrofit/) So your interface would look like this:

public interface RestAppApiInterface {

@FormUrlEncoded
@POST(Constants.URL_LOGIN)
void logIn(@Field("username") String username, @Field("password") String password, Callback<User>pCallback);

Exceptions are handled in Callbacks failure method. And no need to execute it in seperate thread then.

Use:

apiInterface.logIn("username","p@55w0rd", new Callback<User>() {
                @Override
                public void success(User u, Response response) {
                    //on success
                }

                @Override
                public void failure(RetrofitError error) {
                    //on failure
                }
            });

Upvotes: 0

frankelot
frankelot

Reputation: 14409

Here's what I ended up doing: I don't know if it's a good solutions but it works. (I'll just have to remember to catchthis exception everytime I use the interface.

        try {
            user = apiInterface.logIn(params[0], params[1]);
            if (user != null) {
                return Constants.LOG_IN_OK;
            } else {
                return Constants.LOG_IN_INVALID_CREDENTIALS;
            }
        } catch (RetrofitError e) {
            return Constants.LOG_IN_SERVER_NOT_FOUND;
        }

Upvotes: 0

Ivan Bartsov
Ivan Bartsov

Reputation: 21066

[Not tested, from the top of my head]

Looks like you could intervene here:

Caused by ... yada yada ...
retrofit.client.UrlConnectionClient.execute(UrlConnectionClient.java:37)

Retrofit's RestAdapter.Builder lets you customize the way you access your backend with setClient() method, so you can go like this:

RestAdapter restAdapter = new RestAdapter.Builder().setClient(
  new Client.Provider() {
    public Client get() {
      return new UrlConnectionClient() {
          @Override
          public Response execute(Request request) {
            // Test avail. / handle exceptions here,
            // call through to the real implementation
            return super.execute();
          }
      };
    }
  });

For actual host availability logic you can try this recipe

Upvotes: 3

Related Questions