Android "ServiceListener" class for listening web services
You may consider abstracting the idea of an HttpService that provides capabilities to make remote endpoint invocations via http. 

interface HtppService {
   &lt;T&gt; T get(URI endpoint, Class&lt;T&gt; responseType);
   &lt;T&gt; T put(URI endpoint, Object body, Class&lt;T&gt; responseType);
   &lt;T&gt; T post(URI endpoint, Object body, Class&lt;T&gt; responseType);
   ///...
}


The advantages are:


You encapsulate the reusable logic of making http remote calls, since many of your services will want to do this over and over.
Your remote services no longer need to worry about how to make remote calls, they will be provided with your own HttpService implementation for that matter. Then you can focus on the important business data.
Your implementations can vary, and today you can have one using OkHttp but tomorrow you might just as well use something like, e.g. Spring RestTemplate.
Also you totally encapsulate and control your dependencies of third-party libraries. In this case, your dependency with OkHttp won't be all over the place, but only in the implementation of this interface.


Wit this interface defined you could first work in the implementation of its methods, expecting that all your remote services would use them.

class OkHttpService implements HttpService {

   private final HttpClient httpClient;

   public(HttpClient httClient) {
      this.httpClient = client;
   }

   public &lt;T&gt; get(URI uri, Class&lt;T&gt; respType) {
     //TODO: implement generic get call
   }

  &lt;T&gt; T put(URI endpoint, Object body, Class&lt;T&gt; responseType) {
     //TODO: implement generic put call
   }

   //etc, etc

}


Then you could finally build your remote service. I would start by defining its interface:

interface AirportService {
  Airport[] getAirportsByCity(String city);
}


Then you can provide an implementation of this service that will make remote calls through your HttpService:

class DefaultAirportService implements AirportService {

   private final String host;
   private final HttpService httpService;

   public DefaultAirportService(String host, HttpService httpService) {
      this.host = host;
      this.httpService = httpService;
   }

   public Airport[] getAirportsByCity(String city) {
      URI endpoint = URI.create(String.format("%s/airports?city=%s", host, city));
      try {
          return httpService.get(endpoint, Airport[].class);
      }
      catch(Exception e) {
        throw AirportServiceException("Failed to get airports for " + city, e);
      }
   }
}


There are few advantages here:


First, by passing an HttpService instance as an argument to the constructor you can easily mock that service and test your AirportService implementation in isolation.
Also, the fact that we accept the host name as one of the arguments will help you configure different instances of your service for different environments. For example, in integrations servers you may want the endpoint to point to a test server.
Finally, you can concentrate on your business logic here, and avoid having to worry about Http calls and how to deal with them.


Once you have reached that point, if you want to encapsulate your service in a runnable object, that is going to be quite simple to do:

AirportService airportService = new DefaultAirpotService("http://localhost:8080", myHttpService);

Runnable runService = new Runnable() {
   public void run() {
      aiportService.getAirportsByCity("Miami"); 
   }
}
new Thread(runService).start();