Retrofit is a framework developed by the Square company for the Android network, RETROFIT2 based on Okhttp, Okhttp is now officially recognized by Google, and a large number of apps are using okhttp to make network requests, Its source details see Okhttp Github.
This article is all in the retrofit2.0+ version based on the discussion, using all the examples from the Watercress API
First let's look at how a complete GET request is implemented:
Create a business request interface with the following specific code:
The code is as follows |
Copy Code |
Public interface Blueservice { @GET ("Book/search") Call<booksearchresponse> Getsearchbooks (@Query ("q") String name, @Query ("tag") String tag, @Query ("start") int start, @Query ("Count") int count); }
|
Here is a little explanation, @GET annotations represent get requests, @Query represent request parameters that will be key=value in the back of the URL
You need to create a retrofit example and complete the appropriate configuration
The code is as follows |
Copy Code |
Retrofit RETROFIT = new Retrofit.builder () . BaseURL ("https://api.douban.com/v2/") . Addconverterfactory (Gsonconverterfactory.create ()) . build (); Blueservice service = retrofit.create (Blueservice.class); |
The BaseURL here is the network request URL relatively fixed address, generally including the request protocol (such as HTTP), domain name or IP address, port number, of course, there will be many other configurations, described in detail below. There is also a Addconverterfactory method that indicates what converters need to be used to resolve the return value, and Gsonconverterfactory.create () indicates that the Gson library is invoked to parse the JSON return value, as described in detail below.
Invoke the request method and get the call instance
Call<booksearchresponse> call = Mblueservice.getsearchbooks ("The Little Prince", "", 0, 3);
Call in fact in retrofit is the use of the network request and processing the return value of the class, calls will be required to join the parameters passed in, where the final URL to get the full address of
Https://api.douban.com/v2/book/search?q=%E5%B0%8F%E7%8E%8B%E5%AD%90&tag=&start=0&count=3
To complete a synchronous or asynchronous request using the call instance
Sync Request
Booksearchresponse response = Call.execute (). body ();
It is important to note that the network request must be done in the child thread, not directly on the UI thread, or it will crash
Asynchronous request
The code is as follows |
Copy Code |
Call.enqueue (New callback<booksearchresponse> () { @Override public void Onresponse (call<booksearchresponse> call, response<booksearchresponse> Response) { Asynctext.settext ("Asynchronous request Result:" + response.body (). Books.get (0). Alttitle); } @Override public void OnFailure (call<booksearchresponse> call, Throwable t) { } }); |
Second, how to use
First you need to introduce the required third package in the Build.gradle file, configured as follows:
The code is as follows |
Copy Code |
Compile ' com.squareup.retrofit2:retrofit:2.1.0 ' Compile ' com.squareup.retrofit2:converter-gson:2.1.0 ' Compile ' com.squareup.retrofit2:adapter-rxjava:2.1.0 '
|
After the introduction of the third package you can then use retrofit to make network requests. The next step is to make a further explanation of the different request methods.
Get method
1. @Query
The Get method request parameters are key=value to the URL, and retrofit provides two ways to set the request parameters. The first is to add @query annotations directly to the interface as mentioned above, and there is a way to do this through interceptor, directly looking at how the request parameter can be added through interceptor.
code is as follows |
copy code |
public class Custominterceptor implements Interceptor { @Override public Response Intercept (Chain Chain) throws IOException { request request = Chain.request (); Httpurl httpurl = Request.url (). Newbuilder () Addqueryparameter ("token", "Tokenvalue ") build (); request = Request.newbuilder (). URL (httpurl). build (); return chain.proceed (Request); } } |
Addqueryparameter is the specific code to add request parameters, this method is more suitable for all requests that need to be added to the parameters, generally the current network request will add token as the user identity, then this approach is more appropriate.
After you create a custom interceptor, you also need to create a client at retrofit to complete the add
The code is as follows |
Copy Code |
Addinterceptor (New Custominterceptor ())
|
2. @QueryMap
If there are more query parameters, you can integrate all the parameters into a map in a @querymap way, and the GET request method in the above article as an example
The code is as follows |
Copy Code |
Public interface Blueservice { @GET ("Book/search") Call<booksearchresponse> getsearchbooks (@QueryMap map<string, string> options); }
|
When called, all parameters are assembled in a unified map.
The code is as follows |
Copy Code |
map<string, string> options = new hashmap<> (); Map.put ("Q", "Little Prince"); Map.put ("tag", null); Map.put ("Start", "0"); Map.put ("Count", "3"); Call<booksearchresponse> call = Mblueservice.getsearchbooks (options);
|
3. Query Collection
If you need to add the same key value, but the value has more than one case, one way is to add multiple @query parameters, there is an easy way is to put all the value in the list, and then complete the add under the same @query, the instance code is as follows:
The code is as follows |
Copy Code |
Public interface Blueservice { @GET ("Book/search") Call<booksearchresponse> Getsearchbooks (@Query ("q") list<string> name); }
|
The resulting URL address is
Https://api.douban.com/v2/book/search?q=leadership&q=beyond%20feelings
4. Query is not required
If the request parameter is not required, which means that the server can parse correctly even if the parameter is not passed, how do you implement it? In fact, it is also very simple, the request method definition or need a complete query annotation, a request if you do not need to pass the argument, just fill in null.
For a request to the get that is mentioned at the beginning of the article, the join is called in the following manner
Call<booksearchresponse> call = Mblueservice.getsearchbooks ("The Little Prince", NULL, 0, 3);
The resulting URL address is
Https://api.douban.com/v2/book/search?q=%E5%B0%8F%E7%8E%8B%E5%AD%90&start=0&count=3
5. @Path
If the requested relative address is also required to be passed by the caller, you can use the @path annotation, the sample code is as follows:
@GET ("Book/{id}")
Call<bookresponse> GetBook (@Path ("id") String ID);
The business side wants to splice the book ID behind the address, then the path annotation can be dynamically passed in the specific invocation scenario, and the specific invocation method is as follows:
Call<bookresponse> call = Mblueservice.getbook ("1003078");
At this point the URL address is
https://api.douban.com/v2/book/1003078
@Path can be used for any type of request, including Post,put,delete, etc.
POST request
1. @field
Post requests need to place the request parameters in the request body, rather than stitching it behind the URL, to see a simple example
The code is as follows |
Copy Code |
@FormUrlEncoded @POST ("Book/reviews") Call<string> addreviews (@Field ("book") string BookID, @Field ("title") string title, @Field ("content") string content, @Field ("rating") string rating);
|
Here are a few things to explain.
@FormUrlEncoded will automatically adjust the type of the request parameter to application/x-www-form-urlencoded, and if the content passes a parameter of good Luck, the final request is
Content=good+luck
Formurlencoded cannot be used for GET requests
@Field Note holds each request parameter to the request body, and you can add the encoded parameter, which is Boolean, and the specific usage is
@Field (value = "book", encoded = True) String Book
If the encoded parameter is true, the Key-value-pair will be encoded to encode the Chinese and special characters for conversion
2. @FieldMap
The above POST request has 4 request parameters, if there are more request parameters, then pass one of the parameters are cumbersome and error-prone, this time can be used Fieldmap
The code is as follows |
Copy Code |
@FormUrlEncoded @POST ("Book/reviews") Call<string> addreviews (@FieldMap map<string, string> fields);
|
3. @Body
If there are multiple POST request parameters, it should be better to unify the package into the class, which is very convenient to maintain
The code is as follows |
Copy Code |
@FormUrlEncoded @POST ("Book/reviews") Call<string> Addreviews (@Body reviews reviews); public class Reviews { Public String Book; Public String title; public String content; public String rating; } |
Other Request methods
In addition to get and post requests, HTTP requests include put,delete and so on, which are similar to post, so they are not introduced separately.
Upload
Upload because need to use multipart, so need to take out a separate introduction, first look at a specific upload example
First, you need to create a new interface to define the upload method.
The code is as follows |
Copy Code |
Public interface Fileuploadservice { Upload a single file @Multipart @POST ("Upload") Call<responsebody> UploadFile ( @Part ("description") requestbody description, @Part multipartbody.part file); Upload Multiple Files @Multipart @POST ("Upload") Call<responsebody> Uploadmultiplefiles ( @Part ("description") requestbody description, @Part Multipartbody.part File1, @Part Multipartbody.part file2); } |
Next we need to implement two tool methods in the activity and fragment, the following code:
The code is as follows |
Copy Code |
public static final String multipart_form_data = "Multipart/form-data"; @NonNull Private Requestbody createpartfromstring (String descriptionstring) { Return Requestbody.create ( Mediatype.parse (Multipart_form_data), descriptionstring); } @NonNull Private Multipartbody.part Preparefilepart (String partname, Uri Fileuri) { File File = Fileutils.getfile (this, Fileuri); Create a Requestbody instance for file Requestbody RequestFile = Requestbody.create (Mediatype.parse (multipart_form_data), file); Multipartbody.part to complete the final upload with the help of filename Return MultipartBody.Part.createFormData (PartName, File.getname (), requestfile); } |
Okay, so here's the final upload file code.
The code is as follows |
Copy Code |
Uri File1uri = ...//get from file selector or camera Uri File2uri = ... Create an uploaded service instance Fileuploadservice Service = Servicegenerator.createservice (Fileuploadservice.class); Create the part of the file (photo, video, ...) Multipartbody.part body1 = Preparefilepart ("video", File1uri); Multipartbody.part body2 = Preparefilepart ("thumbnail", File2uri); Add additional part Requestbody Description = createpartfromstring ("Hello, this is description speaking"); The last asynchronous request operation is performed Call<responsebody> call = Service.uploadmultiplefiles (description, body1, body2); Call.enqueue (New callback<responsebody> () { @Override public void Onresponse (call<responsebody> call, Response<responsebody> Response) { LOG.V ("Upload", "success"); } @Override public void OnFailure (call<responsebody> call, Throwable t) { LOG.E ("Upload error:", T.getmessage ()); } }); |
Iii. Other matters that must be known
1. Add a custom header
Retrofit provides two ways to define HTTP request header parameters: Static methods and dynamic methods, static methods cannot vary with different requests, and header information is fixed at initialization time. Dynamic methods, however, must be set separately for each request.
static method
The code is as follows |
Copy Code |
Public interface Blueservice { @Headers ("cache-control:max-age=640000") @GET ("Book/search") Call<booksearchresponse> Getsearchbooks (@Query ("q") String name, @Query ("tag") String tag, @Query ("start") int start, @Query ("Count") int count); }
|
Of course you want to add multiple header parameters is also OK, the writing is very simple
The code is as follows |
Copy Code |
Public interface Blueservice { @Headers ({ "Accept:application/vnd.yourapi.v1.full+json", "User-agent:your-app-name" }) @GET ("Book/search") Call<booksearchresponse> Getsearchbooks (@Query ("q") String name, @Query ("tag") String tag, @Query ("start") int start, @Query ("Count") int count); }
|
In addition, you can define a static request header by interceptor.
code is as follows |
copy code |
public class Requestinterceptor implements Interceptor { @Override public Response Intercept (Chain Chain) throws IOException { Request original = Chain.request (); Request request = Original.newbuilder () header ("User-agent", "Your-app-name") header ("Accept", "Application/vnd.yourapi.v1.full+json") Method (Original.method (), Original.body ()) build (); return chain.proceed (Request); } } |
Add header parameter request provides two methods, one is header (key, value), and the other is. AddHeader (key, value), the difference is that header () if there is a duplicate will be overwritten, and AddHeader () Allow header existence of same key value
Then, when Okhttp creates a client instance, add Requestinterceptor
The code is as follows |
Copy Code |
private static Okhttpclient getnewclient () { return new Okhttpclient.builder () . Addinterceptor (New Requestinterceptor ()) . ConnectTimeout (Default_timeout, Timeunit.seconds) . build (); }
|
Dynamic method
The code is as follows |
Copy Code |
Public interface Blueservice { @GET ("Book/search") Call<booksearchresponse> Getsearchbooks ( @Header ("Content-range") String Contentrange, @Query ("q") string name, @Query ("tag") string tag, @Query ("start") int start, @Query ("Count") int count); } |
2. Network Request log
When debugging a network request, you often need to focus on the request parameters and return values in order to determine and locate the problem, retrofit official provides a very easy to view the log interceptor, you can control the type of printing information you need, the use of the method is simple.
First you need to introduce logging-interceptor in the Build.gradle file.
Compile ' com.squareup.okhttp3:logging-interceptor:3.4.1 '
Like the Custominterceptor and requestinterceptor mentioned above, add to the okhttpclient creation, complete the sample code as follows:
code is as follows |
copy code |
private static okhttpclient getnewclient () { Httplogginginterceptor logging = new Httplogginginterceptor (); Logging.setlevel (HttpLoggingInterceptor.Level.BODY); return new Okhttpclient.builder () Addinterceptor (New Custominterceptor ()) Addinterceptor (logging) connecttimeout ( Default_timeout, Timeunit.seconds) build (); } |
Httplogginginterceptor provides 4 levels of control of the type of print information, respectively, None,basic,headers,body, followed by the corresponding type of printing information.
NONE
No log information
Basic
Print request type, URL, request body size, return value status, and return value size
D/httplogginginterceptor$logger:--> post/upload http/1.1 (277-byte body)
D/httplogginginterceptor$logger: <--http/1.1 OK (543ms, -1-byte body)
Headers
Print header information for return request and return values, request type, URL, and return value status code
The code is as follows |
Copy Code |
<--OK https://api.douban.com/v2/book/search?q=%e5%b0%8f%e7%8e%8b%e5%ad%90&start=0&count=3& Token=tokenvalue (3787MS) D/okhttp:date:sat, Aug 2016 14:26:03 GMT D/okhttp:content-type:application/json; Charset=utf-8 D/okhttp:transfer-encoding:chunked D/okhttp:connection:keep-alive D/okhttp:keep-alive:timeout=30 D/okhttp:vary:accept-encoding D/okhttp:expires:sun, 1 2006 01:00:00 GMT D/okhttp:pragma:no-cache D/okhttp:cache-control:must-revalidate, No-cache, private D/OKHTTP:SET-COOKIE:BID=D6UTQR5N9I4; Expires=sun, 06-aug-17 14:26:03 GMT; domain=.douban.com; path=/ D/okhttp:x-douban-newbid:d6utqr5n9i4 D/okhttp:x-dae-node:dis17 D/okhttp:x-dae-app:book D/okhttp:server:dae D/okhttp: <--End HTTP Body Print the header and body information for the request and return values <--OK https://api.douban.com/v2/book/search?q=%E5%B0%8F%E7%8E%8B%E5%AD%90&tag=&start=0&count= 3&token=tokenvalue (3583MS)
D/okhttp:connection:keep-alive
D/okhttp:date:sat, Aug 2016 14:29:11 GMT
D/okhttp:keep-alive:timeout=30
D/okhttp:content-type:application/json; Charset=utf-8
D/okhttp:vary:accept-encoding
D/okhttp:expires:sun, 1 2006 01:00:00 GMT
D/okhttp:transfer-encoding:chunked
D/okhttp:pragma:no-cache
D/okhttp:connection:keep-alive
D/okhttp:cache-control:must-revalidate, No-cache, private
D/okhttp:keep-alive:timeout=30
D/okhttp:set-cookie:bid=esnahto1_os; Expires=sun, 06-aug-17 14:29:11 GMT; domain=.douban.com; path=/
D/okhttp:vary:accept-encoding
D/okhttp:x-douban-newbid:esnahto1_os
D/okhttp:expires:sun, 1 2006 01:00:00 GMT
D/okhttp:x-dae-node:dis5
D/okhttp:pragma:no-cache
D/okhttp:x-dae-app:book
D/okhttp:cache-control:must-revalidate, No-cache, private
D/okhttp:server:dae
D/okhttp:set-cookie:bid=5qefvyuz3ku; Expires=sun, 06-aug-17 14:29:11 GMT; domain=.douban.com; path=/
D/okhttp:x-douban-newbid:5qefvyuz3ku
D/okhttp:x-dae-node:dis17
D/okhttp:x-dae-app:book
D/okhttp:server:dae
D/okhttp: {"Count": 3, "Start": 0, "Total": 778, "books": [{"rating": {"Max": "Numraters": 202900, "average": "9.0", "min ": 0}," subtitle ":" "," Author ": [" [FA] Saint Exupery "]," pubdate ":" 2003-8 "," tags ": [{" Count ": 49322," name ":" The Little Prince "," title ":" The Little Prince " },{"Count": 41381, "name": "Fairy Tale", "title": "Fairy Tale"},{"Count": 19773, "name": "Saint Exupery", "title": "Saint Exupery"}
D/okhttp: <--End HTTP (13758-byte) |
3. Set the full URL for a request
What if one of your requests does not begin with Base_url? Don't worry, the way is simple, look at the example below you can understand
The code is as follows |
Copy Code |
Public interface Blueservice { @GET Public call<responsebody> profilepicture (@Url String Url); } Retrofit RETROFIT = Retrofit.builder () . BaseURL ("https://your.api.url/"); . build (); Blueservice service = retrofit.create (Blueservice.class); Service.profilepicture ("Https://s3.amazon.com/profile-picture/path"); |
The complete URL address can be passed directly in the form of a @url annotation.
4. Cancel Request
Call provides the Cancel method to cancel the request if the request has not yet been executed
The code is as follows |
Copy Code |
String fileUrl = "Http://futurestud.io/test.mp4"; Call<responsebody> call = Downloadservice.downloadfilewithdynamicurlsync (FILEURL); Call.enqueue (New callback<responsebody> () { @Override public void Onresponse (call<responsebody> call, response<responsebody> Response) { LOG.D (TAG, "request Success"); } @Override public void OnFailure (call<responsebody> call, Throwable t) { if (call.iscanceled ()) { LOG.E (TAG, "request was cancelled"); } else { LOG.E (TAG, "other larger issue, i.e. no network connection?"); } } }); } Triggers an action, such as a button that the user clicked to cancel the request Call.cancel (); } |
Four, the conclusion
About retrofit commonly used methods have been introduced, and some requests due to the confidentiality of work, so there is no release, but the basic methods and operations are there, in the text mentioned in the code can achieve the function you want