Retrofit has been running for years as a library to simplify HTTP requests, and version 2.0 does just that. Version 2.0, however, fixes some longstanding design issues and adds more powerful features than ever before. In this share of NYC 2015, Jake Wharton’s talk covers all of Retrofit 2.0’s new features and provides a comprehensive overview of how Retrofit 2.0 works.

About the Author: Jake Wharton

Jake Wharton is an engineer at Square. Spent the last five years fighting bad code and apis. Attend conferences regularly to discuss the plague of design that affects millions of developers.

@jakewharton

Save the date for Droidcon SFIn March — a conference with best-in-class presentations from leaders in all parts of the Android ecosystem.

Introduction to the(0:00)

My name is Jake Wharton and I work at Square. One naive person once said: “Retrofit 2 will be released before the end of the year.” That person was me at DroidCon in New York last year. However, the truth is Retrofit 2 will be released by the end of the year, this time I promise!

Retrofit went open source five years ago and was one of Square’s earliest open source projects. When Retrofit started, it was just a lucky bag that we used in various open source projects: shake detection in the beginning, HTTP Client, and now TAP. Most of the functionality was done by Bob Lee, and I took over about three years ago. It took three years to complete version 1.0, and then open source. Since then, there have been 18 releases.

Good place for Retrofit 1(he)

Retrofit already has a lot of nice features. Retrofit can use interfaces, methods, and parameter Annotations to declaratively define how a request should be created. For example, here is an example of how to request the GitHub API:

interface GitHubService { @GET("/repos/{owner}/{repo}/contributors") List repoContributors( @Path("owner") String owner,  @Path("repo") String repo); }Copy the code

The HTTP client behind Retrofit, as well as the serialization mechanism (JSON/XML protocol) are pluggable, so you can choose what works for you. When Retrofit first came out, it only supported Apache’s HTTP client. Before 1.0 was released, we added SUPPORT for URL Connection and OkHttp. If you want to join any other HTTP client, you can simply join. This feature is great and gives us the ability to support different custom clients.

builder.setClient(new UrlConnectionClient());
builder.setClient(new ApacheClient());
builder.setClient(new OkClient());

builder.setClient(new CustomClient());Copy the code

The serialization function is also replaceable. The default is GSON, but you can also use Jackson instead.

interface GitHubService { @GET("/repos/{owner}/{repo}/contributors") List repoContributors( @Path("owner") String owner,  @Path("repo") String repo); } builder.setConverter(new GsonConverter()); builder.setConverter(new JacksonConverter());Copy the code

If you’re using some sort of data exchange protocol, such as the Protocol Buffer, Retrofit also supports Google’s Protobuf, as well as XML protocol conversions (if you’re not afraid to mess with them yourself).

interface GitHubService {
  @GET("/repos/{owner}/{repo}/contributors")
  ContributorResponse repoContributors(
      @Path("owner") String owner,
      @Path("repo") String repo);
}

builder.setConverter(new ProtoConverter());
builder.setConverter(new WireConverter());

builder.setConverter(new SimpleXMLConverter());

builder.setConverter(new CustomConverter());Copy the code

The serialization part, like the client part, is replaceable. If you want to introduce or implement your own serialization component, that’s fine.

There are many ways you can implement sending requests, such as sending requests synchronously

interface GitHubService { @GET("/repos/{owner}/{repo}/contributors") List repoContributors( @Path("owner") String owner,  @Path("repo") String repo); } List contributors = gitHubService.repoContributors("square", "retrofit");Copy the code

The difference between async and async is that async declares a callback function on the last argument:

interface GitHubService {
  @GET("/repos/{owner}/{repo}/contributors")
  void repoContributors(
      @Path("owner") String owner,
      @Path("repo") String repo,
      Callback> cb);
}

service.repoContributors("square", "retrofit", new Callback>() {
  @Override void success(List contributors, Response response) {
    // ...
  }


  @Override void failure(RetrofitError error) {
    // ...
  }
});Copy the code

After 1.0, we also supported RxJava, which proved to be a very popular feature.

interface GitHubService {
  @GET("/repos/{owner}/{repo}/contributors")
  Observable> repoContributors(
      @Path("owner") String owner,
      @Path("repo") String repo);
}

gitHubService.repoContributors("square", "retrofit")
    .subscribe(new Action1>() {
      @Override public void call(List contributors) {
        // ...
      }
    });Copy the code

Retrofit 1: Not good enough(4:58)

Unfortunately, no library is perfect, and Retrofit is no exception. To support replaceable functional modules, we had to nest so many components that the number of classes became a sore point, both because the library was so fragile and because we couldn’t modify the exposed API.

If you want to manipulate the data returned from a request, such as the Header part or URL, and you also want to manipulate the serialized part of the data, this is not possible in Retrofit 1.0.

interface GitHubService { @GET("/repos/{owner}/{repo}/contributors") List repoContributors( @Path("owner") String owner,  @Path("repo") String repo); @GET("/repos/{owner}/{repo}/contributors") Response repoContributors2( @Path("owner") String owner, @Path("repo") String repo); }Copy the code

In the GitHub example above, we returned a contributor list that you can deserialize with different Converter contributors. However, say you want to read the header part of a reponse. There is no way to read the response unless you set an endpoint to take over the reponse. Since there are no deserialized objects in the Response Header data, you won’t get contributor objects without deserialization.

I just talked about synchronous and asynchronous, and RxJava, which is great to use, but it’s a little rigid to use. For example, we need both asynchronous and synchronous calls in some scenarios. In Retrofit 1.0, you had to declare this method twice, like this:

interface GitHubService { @GET("/repos/{owner}/{repo}/contributors") List repoContributors( @Path("owner") String owner,  @Path("repo") String repo); @GET("/repos/{owner}/{repo}/contributors") void repoContributors( @Path("owner") String owner, @Path("repo") String repo, Callback> cb); }Copy the code

RxJava has a similar problem. Thankfully, you only have to declare it once to use RxJava. To do this, we’ve added support for RxJava to the core code to help return Observable objects.

interface GitHubService { @GET("/repos/{owner}/{repo}/contributors") Observable> repoContributors( @Path("owner") String  owner, @Path("repo") String repo); }Copy the code

We’re probably already familiar with how to create Observables in Retrofit. But what if you need something else? For example, we have no plans to support ListenableFuture that uses Guava, and CompleteableFuture that uses Java 8. After all, Retrofit 1 was built on Android, which still uses Java 6.

The Converter didn’t work very efficiently in Retrofit 1. Here is the code to create a custom Converter in Retrofit 1, which is very simple:

interface Converter {
  Object fromBody(TypedInput body, Type type);
  TypedOutput toBody(Object object);
}Copy the code

The custom Converter receives an object and returns a formatted HTTP object. The problem is that after we pass in Response and a format Type parameter that we want to convert, Converter has to figure out exactly how to deserialize it, which is complicated and time-consuming to implement. Although some libraries do cache objects, it is still inefficient.

interface GitHubService { @GET("/search/repositories") RepositoriesResponse searchRepos( @Query("q") String query, @Query("since") Date since); } /search/repositories? q=retrofit&since=2015-08-27 /search/repositories? q=retrofit&since=20150827Copy the code

Sometimes, declarative apis run into minor problems. For example, as in the example above, you have an interface that needs to pass in a Date, but a Date can be represented in many different formats. Some interfaces may require a string, while others may require a delimited date representation (especially for objects that are much more complex than dates, there may be more representation methods).

That’s basically a need Retrofit 1 couldn’t solve. How do we fix it?

Retrofit 2 (much)

When we developed Retrofit2, we wanted to locate and solve all of the problems that people had had with Retrofit 1 over the years.

Call (10:30)

First things first: Retrofit2 has a new type. If you’re familiar with making API requests using OkHttp, you’re probably familiar with one of these classes: Call. Retrofit 2 now has a call method as well. The syntax is basically the same as OkHttp, except that this function knows how to deserialize data. It knows how to convert HTTP responses into objects.

In addition, each call object instance can only be used once, so request and Response are one-to-one. You can actually create a Clone instance using the Clone method with minimal overhead. For example, you can clone a previous instance every time you decide to send a request.

Another big step forward is that 2.0 supports both synchronization and asynchrony within a type. At the same time, a request can actually be terminated. The terminate operation performs a cancel operation on the underlying HTTP client. Even ongoing requests can be cut off immediately.

interface GitHubService {
  @GET("/repos/{owner}/{repo}/contributors")
  Call> repoContributors(
      @Path("owner") String owner,
      @Path("repo") String repo);
}

Call> call =
    gitHubService.repoContributors("square", "retrofit");Copy the code

This Call object is the parameterized object returned from your API. Call the same function name as the interface name, and you’ll get an instance. We can call its execute method directly, but note that this method can only be called once.

Call> call =
    gitHubService.repoContributors("square", "retrofit");

response = call.execute();

// This will throw IllegalStateException:
response = call.execute();

Call> call2 = call.clone();
// This will not throw:
response = call2.execute();Copy the code

When you try to call it a second time, you will get a failed error. In fact, it is possible to clone an instance directly at a very low cost. When you want to make multiple requests to an interface, clone a new, identical, usable object.

To implement asynchrony, call the enQueue method. Now we can implement synchronization and asynchrony in a single declaration!

Call> call = gitHubService.repoContributors("square", "retrofit"); call.enqueue(new Callback>() { @Override void onResponse(/* ... * /) {/ /... } @Override void onFailure(Throwable t) { // ... }});Copy the code

After you have queued some asynchronous requests, or even if you are performing a synchronous request, you can always call the cancel method to cancel the request:

Call> call =
    gitHubService.repoContributors("square", "retrofit");

call.enqueue(         );
// or...
call.execute();

// later...
call.cancel();Copy the code

Parameterized Response Object (13:48)

Another new feature is the parameterized Response type. The Response object adds important metadata that was previously ignored: the reponse code, the Response message, and the headers.

class Response {
  int code();
  String message();
  Headers headers();

  boolean isSuccess();
  T body();
  ResponseBody errorBody();
  com.squareup.okhttp.Response raw();
}Copy the code

It also provides a handy function to help you determine whether the request completed successfully by checking if the response code is 200. Then you get the body part of the response, and there’s a separate method to get the Error body. Basically, a return code appears and the corresponding function is called. Only when the response is successful will we deserialize it and put the deserialized results into the body callback. If a network success response is returned (return code: 200) and return false, we don’t actually know what the ResponseBody is, we just give you the ResponseBody type.

These are the two major changes in declaring interfaces.

Dynamic URL Parameter(direction)

Dynamic URL parameters have been a headache for me for years, and we’ve finally solved it! If you make multiple requests to GitHub and receive one response, it will usually look something like this:

interface GitHubService {
  @GET("/repos/{owner}/{repo}/contributors")
  Call> repoContributors(
      @Path("owner") String owner,
      @Path("repo") String repo);
}

Call> call =
    gitHubService.repoContributors("square", "retrofit");
Response> response = call.execute();

// HTTP/1.1 200 OK
// Link: 
page=2>; rel="next", ; rel="last"
// ...Copy the code

If you want to do paging, you’ll have to analyze the urls yourself. GitHub may already cache data from the Header Link address list in server memory, so that when you request the address they indicate, they don’t have to go through the hassle of retrieving data from their database, and it’s faster. However, in Retrofit 1.0, there was no way to directly implement the requested address that GitHub Server returned in the header.

Using our new Response type, we can also write methods to read custom fields, such as the next page address in the example above, in addition to the metadata I just mentioned:

Response> response = call.execute();

// HTTP/1.1 200 OK
// Link: 
page=2>; rel="next", ; rel="last"
// ...

String links = response.headers().get("Link");
String nextLink = nextFromGitHubLinks(links);

// https://api.github.com/repositories/892275/contributors?page=2Copy the code

This may be slightly different from the interface generation address above.

Dynamic URLS are used for continuous requests. After the first request, if the result has an address for the next request, before you might have to write a separate interface to handle this situation, now you don’t have to bother so much.

interface GitHubService {
  @GET("/repos/{owner}/{repo}/contributors")
  Call> repoContributors(
      @Path("owner") String owner,
      @Path("repo") String repo);

  @GET
  Call> repoContributorsPaginate(
      @Url String url);
}Copy the code

Retrofit 2.0 has a new annotation: @URL, which allows you to pass in a requested Url directly.

With this method, we can directly pass in the address of the next page, is not everything smooth:

String nextLink = nextFromGitHubLinks(links);

// https://api.github.com/repositories/892275/contributors?page=2

Call> nextCall =
    gitHubService.repoContributorsPaginate(nextLink);Copy the code

That way, we can get the second page by calling repoContributorsPaginate, and then request the third page through the header of the second page. You’ve probably seen this kind of design in many apis, and it’s a big problem for many people in Retrofit 1.

More efficient ConvertersThis was the ()

There was a problem with Converter in Retrofit 1. Most of you probably haven’t, but it’s a problem inside the library. In Retrofit 2, we’ve addressed this issue and started supporting multiple Converters.

Previously, if you had a situation where one API request required JSON deserialization and another API request required PROTO deserialization, the only solution was to declare the two interfaces separately.

interface SomeProtoService {
  @GET("/some/proto/endpoint")
  Call someProtoEndpoint();
}

interface SomeJsonService {
  @GET("/some/json/endpoint")
  Call someJsonEndpoint();Copy the code

The reason for this is that a REST Adapter can only bind to one Converter object. We took the trouble to solve this because interface declarations are meant to be semantic. API interfaces should be grouped by functionality, such as the Account interface, the User interface, or the Twitter-related interface. Differences in return formats should not stop you from grouping.

Now, you can put them all together:

interface SomeService {
  @GET("/some/proto/endpoint")
  Call someProtoEndpoint();

  @GET("/some/json/endpoint")
  Call someJsonEndpoint();
}Copy the code

I’ll briefly mention how this works, because it’s important to understand how Converter calls when writing code.

Look at our code above: the first method returns a Proto object.

SomeProtoResponse – > Proto? Yes!

The principle is very simple, in essence, each Converter is asked if they can handle a certain type. We asked Proto converter: “Hi, can you handle SomeProtoResponse?” And then it does its best to determine if it can handle the type. We all know that Protobuffs inherit from a class called Message or Message Lite. So, the usual way to tell is to check whether the class inherits from Message.

When faced with a JSON type, first ask proto Converter, and proto Converter will see that this is not an inherited Message and reply no. Let’s move on to the next JSON Converter. JSON Converter replies that I can!

SomeJsonResponse – > Proto? No! – > JSON? Yes!

Because JSON has no inheritance constraints. So there are no exact criteria for determining whether an object is a JSON object. So much so that JSON converters will reply to any data and say, “I can handle it!” Keep in mind that the JSON Converter must be placed last, otherwise it will not be what you expected.

Another thing to note is that the default Converter is no longer available. Retrofit will report an error if it does not explicitly declare that a Converter is available: it reminds you that no Converter is available. Since the core code no longer relies on serialization-related third-party libraries, we still provide support for Converter, but you’ll need to introduce these dependencies yourself and explicitly declare what Converter Retrofit needs to use.

More alternative execution mechanisms(22:38)

Previously, Retrofit had a rigid execution process. In Retrofit 2, we tweaked the whole process to be pluggable, allowing multiple processes at once. It’s very similar to how converter works.

For example, if you have a method that returns a Call object, Call is the built-in Converter type. For example, the implementation mechanism of Retrofit 2:

interface GitHubService { @GET("/repos/{owner}/{repo}/contributors") Call> repoContributors( @Path("owner") String owner, @Path("repo") String repo); .Copy the code

Now, you can customize these. Or use one of the ones we provide:

. @GET("/repos/{owner}/{repo}/contributors") Observable> repoContributors2( @Path("owner") String owner, @Path("repo") String repo); @GET("/repos/{owner}/{repo}/contributors") Future> repoContributors3( @Path("owner") String owner, @Path("repo") String repo); }Copy the code

Retrofit 2.0 still supports RxJava, but it is now separate. (If you want something else, you can write your own.) How does supporting different execution at the same time work?

interface GitHubService { @GET("/repos/{owner}/{repo}/contributors") Call> repoContributors(..) ; @GET("/repos/{owner}/{repo}/contributors") Observable> repoContributors2(..) ; @GET("/repos/{owner}/{repo}/contributors") Future> repoContributors3(..) ; }Copy the code

Which exection needs to be called is determined by the return type. For example, if we return Call, our entire execution mechanism will say, “Hey, do you know how to handle Call?” If it’s RxJava, it says, “I don’t know, I just know what Observable does.” . Then we asked the internal Converter and he just answered, “Yes! I will!” .

Call – > RxJava? No! – > Call? Yes!

Observables work the same way. We also ask RxJava and it says, “I can handle this” :

interface GitHubService { @GET("/repos/{owner}/{repo}/contributors") Call> repoContributors(..) ; @GET("/repos/{owner}/{repo}/contributors") Observable> repoContributors2(..) ; @GET("/repos/{owner}/{repo}/contributors") Future> repoContributors3(..) ; }Copy the code

Observables – > RxJava? Yes!

If you don’t have a corresponding Converter, that means we can’t verify the type of response. For example: If asked if there is a way to deal with Future, both of them will say “no”.

interface GitHubService { @GET("/repos/{owner}/{repo}/contributors") Call> repoContributors(..) ; @GET("/repos/{owner}/{repo}/contributors") Observable> repoContributors2(..) ; @GET("/repos/{owner}/{repo}/contributors") Future> repoContributors3(..) ; }Copy the code

Future – > RxJava? No! – > Call? No! – > Throw!

This will return an Exception, meaning that neither of these or the built-in mechanisms can handle this type. We’ll talk more about how that works later.

OkHttp provides support(24:17).

Retrofit 2 now relies on OkHttp, and this part no longer supports replacement. This is a controversial issue. But hopefully I can prove why it was the right decision.

OkHttp is now small and focused, with lots of nice apis. We have an interface mapping to OkHttp in Retrofit 2, which basically has all the features we need, including all the abstract classes mentioned. These are awesome! This is a great way to reduce the size of Retrofit’s library. We ended up reducing Retrofit’s size by 60 percent while adding more features.

OkHttp provides support (and Okio!)(yea)

Another benefit of using OkHttp in Retrofit 2 is that we can export OkHttp directly as a public interface. You’ve probably seen a Response Body in an Error Body method or a response. Obviously, we returned OkHttp’s Response body directly in Retrofit’s Reponse object. We are in the process of exporting these types, and OkHttp’s types have basically replaced some of Retrofit 1.0’s interfaces with better and cleaner apis.

Behind OkHttp is a library called Okio that provides IO support. I gave a talk about this library at Droidcon Montreal. I talked about why it’s the better choice of many IO libraries, why it’s extremely efficient, and why you should use them. I also mentioned Retrofit 2 in my talk when it was still a concept in my head. Retrofit 2 is now implemented.

Efficiency of Retrofit 2(they)

I made this diagram to show that Retrofit is much more efficient than Retrofit 1 and other possible solutions, thanks to the hard dependencies and abstractions I just mentioned. Let me take you to the table in the video above. So be sure to watch this part of my talk!

Initialization – Retrofit type(came)

Now, let’s take a look at how Retrofit types replace REST Adapter types and how to initialize them. The original method was called endpoint, but now we call it baseUrl. BaseUrl is the URL of the Server you requested. Here is an example of requesting the GitHub Api:

Retrofit retrofit = new Retrofit.Builder()
    .baseUrl("https://api.github.com")
    .build();

interface GitHubService {
  @GET("/repos/{owner}/{repo}/contributors")
  Call> repoContributors(
      @Path("owner") String owner,
      @Path("repo") String repo);
}

GitHubService gitHubService = retrofit.create(GitHubService.class);Copy the code

We declare our own interface, which we call the create method, which is consistent with Retrofit 1. Next, let’s generate an implementation of the interface so that the interface methods can be called directly.

So when we call this Repomolecule method, Retrofit creates that URL. If we pass the Square and Retrofit strings as the owner and REPO parameters, respectively. We will get the URL:https://api.github.com/repos/square/retrofit/contributors. Within Retrofit, Retrofit uses OkHttp’s HTTP URL type as the baseUrl, and then the resolve method takes the relative address and concatenates it with baseUrl, and then initiates a request. Next I’ll show you how to change API prefixes like V3.

Retrofit retrofit = new Retrofit.Builder()
    .baseUrl("https://api.github.com/v3/")
    .build();

interface GitHubService {
  @GET("/repos/{owner}/{repo}/contributors")
  Call> repoContributors(
      @Path("owner") String owner,
      @Path("repo") String repo);
}Copy the code

While this isn’t the real GitHub API, there are plenty of real world apis that are made up of such prefixes and paths. Call the same method, URL will be parsed out is this: https://api.github.com/repos/square/retrofit/contributors. You can see that there is no V3 after the host address, because the URL of the address starts with a slash, whereas in HTTP, the slash begins with an absolute suffix path. Retrofit 1 forces you to add the prefix slash for semantic constraints and concatenate the baseUrl with relative addresses. Now, for specification reasons, we have distinguished between these two types of addresses.

interface GitHubService { @GET("repos/{owner}/{repo}/contributors") Call> repoContributors( @Path("owner") String owner,  @Path("repo") String repo); }Copy the code

The prefix/indicates an absolute path. Remove the prefixed/and you will get the correct full URL that contains the v3 path.

Retrofit retrofit = new Retrofit.Builder() .baseUrl("https://api.github.com/v3/") .build(); interface GitHubService { @GET("repos/{owner}/{repo}/contributors") Call> repoContributors( @Path("owner") String owner,  @Path("repo") String repo); } // https://api.github.com/v3/repos/square/retrofit/contributorsCopy the code

Since we now rely on OkHttp, there is no abstraction at the Http Client layer. It is now possible to pass a configured OkHttp instance. For example, configure interceptors, or an SSL Socket factory class, or a specific value for timeouts. (OkHttp has default timeouts, which you don’t really need to set if you don’t want to customize, but if you want to set them, here’s an example of how to do it.)

OkHttpClient client = new OkHttpClient(); client.interceptors().add(..) ; Retrofit retrofit = new Retrofit.Builder() .baseUrl("https://api.github.com") .client(client) .build();Copy the code

If you want to specify a particular Converter or execute mechanism, that’s when you add it. For example: We can set up one or more Converter for GSON. You can also set a Converter to the Protocol Buffer.

Retrofit retrofit = new Retrofit.Builder()
    .baseUrl("https://api.github.com")
    .addConverterFactory(GsonConverterFactory.create())
    .addConverterFactory(ProtoConverterFactory.create())
    .build();Copy the code

I want to emphasize that the order in which you add Converter is important. In that order, we’ll ask each Converter in turn if it can handle a type. What I wrote above was actually wrong. If we tried to deserialize a Proto format, it would be treated as JSON. That’s obviously not what we want. We need to adjust the order because we need to check the Proto Buffer format first, and then JSON.

Retrofit retrofit = new Retrofit.Builder()
    .baseUrl("https://api.github.com")
    .addConverterFactory(ProtoConverterFactory.create())
    .addConverterFactory(GsonConverterFactory.create())
    .build();Copy the code

If you want to use RxJava instead of Call, you need a Call Adapter Factory:

Retrofit retrofit = new Retrofit.Builder()
    .baseUrl("https://api.github.com")
    .addConverterFactory(ProtoConverterFactory.create())
    .addConverterFactory(GsonConverterFactory.create())
    .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
    .build();Copy the code

The Call Adapter Factory is a Factory class that knows how to convert Call instances to other types. Currently, we only have the RxJava type, which converts the Call type to an Observable. If you know RxJava, there’s a new Observable type that fires one item at a time. You can use the Call Adapter Factory to convert to any of these Observables.

scalability(36:50)

Factory, as mentioned earlier, is also extensible. This means you can write your own Call Adapter Facotry. It’s actually a method to implement. Pass it a type, return NULL for rejection, or return an instance of Converter.

SomeJsonResponse

		class ProtoConverterFactory {
  			Converter create(Type type);		null
		}

		class GsonConverterFactory {
			Converter create(Type type);		Converter
		}Copy the code

Look at the example above. If you pass it a JSON Respnose type that is not inherited from Proto, it will say: “I don’t know how to pass this, so I return null.” However, in the case of GSON Converter, it shows that it can handle this type by returning an instance. That’s why this class is a factory class, because we let it produce Converter instances.

If you want to do some customization, it’s very easy to do. The Converter implementation is very similar to the previous one, although instead of typed input and output, we now use OkHttp’s request body and corresponding body.

interface Converter {
  interface Factory {
	Converter  create(Type type);
  }

  T fromBody(ResponseBody body);
  RequestBody toBody(T value);
}Copy the code

This is much more efficient now, because we can actually query those Adapters. For example, GSON has a Type Adapter, and when we ask GSON Converter Factory if it can handle a certain request, the Converter Factory starts to query this adapter, and it will exist as a cache. When we query again, the Adapter can be used directly. This is a very small success and avoids the wear and tear of constant queries.

The Call Adapter has the same pattern. We ask a Call Adapter Factory if it can handle a type, and it will respond in the same way. (for example, it returns null for no). Its API is very simple.

interface CallAdapter {
  interface Factory {
    CallAdapter create(Type type);
  }

  Type responseType();
  Object adapt(Call value);
}Copy the code

We have a way to do that. Passing in a Call instance returns an Observable, single, or future, etc. There’s another way to get this response type: when we declare a series of Contributor calls, we can’t automatically extract those parameterized types, so we basically just ask the Call Adapter to return the Response type as well. If you create an instance for this variable, we request the Call Adapter, which returns the Contributor Type list.

It’s still under construction(40:05)

Retrofit 2 is being perfected! It’s not complete yet, but it works. All of the points I mentioned above are already done, so what’s left to be done?

We don’t have a mature idea of a so-called “parameter handler” yet. We would like it to have multiple maps, or data types and enumerations passed from Guava in the future.

Logging is not done yet, it was in Retrofit 1, but not in Retrofit 2. One advantage of relying on OkHttp is that you can actually use an interceptor to implement the actual low-level request and response logging. Therefore, we don’t need it for the raw request and response, but we probably need logging to record the Java types.

If you’ve ever used the mock module, you’ll notice that it hasn’t been completed yet either, but it will be soon.

Documentation is still scarce.

Finally, I’d like to support Websockets in Retrofit 2 when I have time. It probably won’t be available in 2.0, but I think it will be available in later 2.1 releases.

Release? (he)

I promised Retrofit 2 would be here this year, and it is. We’re not making any promises about when it will come out. I don’t want to make the same joke again with DroidCons 2016. So it will definitely come out this year. I promise. As for August 27, 2015, I have opened a beta version of 2.0.

Dependencies {the compile 'com. Squareup. Retrofit: retrofit: 2.0.0 - walk' compile 'com. Squareup. Retrofit, the converter - gson: 2.0.0 - walk' compile 'com. Squareup. Retrofit: adapter - rxjava: 2.0.0 - walk'}Copy the code

You can rely on it. It already works, and the API is relatively stable. The Converter and Converter factory methods may change in the future, but overall they are useful. If you don’t like or have any questions, please contact me! Thank you very much!

Sign up to be notified of new videos
— We won’t email you for any other reason, ever.