You need to add the necessary dependent libraries in the project first. Edit app / build Gradle file, add the following contents to the dependencies closure:
dependencies { ... implementation 'com.squareup.retrofit2:retrofit:2.6.1' implementation 'com.squareup.retrofit2:converter-gson:2.6.1' }
Use examples
1. Add an entity class App class
data class App(val id: String, val name: String, val version: String)
2. Define an interface file and create an AppService interface
interface AppService { @GET("get_data.json") fun getAppData(): Call<List<App>> }
There are two points to note in the above code. The first is the annotation added on the getAppData() method. Here, a @ GET annotation is used to indicate that when the getAppData() method is called, Retrofit will initiate a GET request, and the request address is the specific parameter we passed in the @ GET annotation. Note that you only need to pass in the relative path of the request address, and the root path will be set later.
The second is that the return value of getAppData() method must be declared as the Call type built-in in Retrofit, and the generic type is used to specify what object the data of the server response should be converted into. Since the server responds to a JSON array containing App data, here we declare the generic as a List. Of course, Retrofit also provides a powerful Call Adapters function to allow us to customize the type of method return value.
3. In activity_main.xml defines a button to test the Retrofit network request event. We can handle the specific network request logic in its click event.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent" > <Button android:id="@+id/getAppDataBtn" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Get App Data" /> </LinearLayout>
Now modify the code in MainActivity:
class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) getAppDataBtn.setOnClickListener { //To build a Retrofit object //baseUrl is used to specify the root path of all Retrofit requests val retrofit = Retrofit.Builder().baseUrl("url") //Specify the conversion library used by Retrofit when parsing data. Here, it is specified as GsonConverterFactory .addConverterFactory(GsonConverterFactory.create()) .build() //Create a dynamic proxy object for this interface val appService = retrofit.create(AppService::class.java) //When the getAppData() method of AppService is called, a call < list < app > > object will be returned, // At this time, we call its enqueue() method again, and Retrofit will make network requests according to the server interface address configured in the annotation, // The data responded by the server will be recalled to the Callback implementation passed in the enqueue() method. //When a request is initiated, Retrofit will automatically start the child thread internally. After the data is recalled to the Callback, // Retrofit will automatically switch back to the main thread. We don't need to consider thread switching in the whole operation process. appService.getAppData().enqueue(object : Callback<List<App>> { //Successful return of data override fun onResponse(call: Call<List<App>>, response: Response<List<App>>) { val list = response.body() if (list != null) { for (app in list) { Log.d("MainActivity", "id is ${app.id}") Log.d("MainActivity", "name is ${app.name}") Log.d("MainActivity", "version is ${app.version}") } } } //Failure situation override fun onFailure(call: Call<List<App>>, t: Throwable) { t.printStackTrace() } }) } } }
4. Handle complex interface address types
First, define an entity class Data
data class Data(val id: String, val content: String)
Case 1: the interface address is static and will never change. For Retrofit, use the following expression:
GET http://example.com/get_data.json
interface ExampleService { @GET("get_data.json") fun getData(): Call<Data> }
Scenario 2: in many scenarios, some contents of the interface address may change dynamically. When this method initiates a request, Retrofit will automatically replace the value of the page parameter with the position of the placeholder to form a legal request address.
GET http://example.com/<page>/get_data.json
interface ExampleService { @GET("{page}/get_data.json") fun getData(@Path("page") page: Int): Call<Data> }
Case 3: when we need to pass in a series of parameters: This is a standard GET request format with parameters. At the end of the interface address, the question mark is used to connect the parameter parts. Each parameter is a key value pair connected with an equal sign, and multiple parameters are separated by an "&" symbol.
GET http://example.com/get_data.json?u=<user>&t=<token>
interface ExampleService { @GET("get_data.json") fun getData(@Query("u") user: String, @Query("t") token: String): Call<Data> }
Here, the user and token parameters are added to the getData() method and declared with the @ Query annotation. In this way, when a network request is initiated, Retrofit will automatically build these two parameters into the request address in the format of a GET request with parameters.
Scenario 4: Retrofit supports all common HTTP request types. Using @ GET, @ POST, @ PUT, @ PATCH, @ DELETE annotations, Retrofit can send corresponding types of requests.
DELETE http://example.com/data/<id>
interface ExampleService { //Because POST, PUT, PATCH and DELETE are different from GET requests, they are more used to operate the data on the server //Data, rather than getting the data on the server, so they usually don't care about the data responded by the server. It can be used at this time //ResponseBody, which means that Retrofit can receive any type of response data and will not parse the response data. @DELETE("data/{id}") fun deleteData(@Path("id") id: String): Call<ResponseBody> }
Scenario 5: what should we write if we need to submit data to the server?
POST http://example.com/data/create {"id": 1, "content": "The description for this data."}
interface ExampleService { //To submit Data using a POST request, you need to PUT the Data in the Body part of the HTTP request. This function can be completed in Retrofit with the @ Body annotation: in this way, when Retrofit sends a POST request, the Data in the Data object will be automatically converted into JSON text and placed in the Body part of the HTTP request, After receiving the request, the server only needs to parse this part of Data from the Body. This method can also be used to submit Data to PUT, PATCH and DELETE requests. @POST("data/create") fun createData(@Body data: Data): Call<ResponseBody> }
Scenario 6: some server interfaces may also require us to specify parameters in the header of the HTTP request
GET http://example.com/get_data.json User-Agent: okhttp Cache-Control: max-age=0
interface ExampleService { @Headers("User-Agent: okhttp", "Cache-Control: max-age=0") @GET("get_data.json") fun getData(): Call<Data> }
//If you want to dynamically specify the value of the header interface ExampleService { //Now, when a network request is initiated, Retrofit will automatically set the value passed in the parameter to //User agent and cache control are two headers, which realizes the function of dynamically specifying header value. @GET("get_data.json") fun getData(@Header("User-Agent") userAgent: String, @Header("Cache-Control") cacheControl: String): Call<Data> }