Skip to content

Latest commit

 

History

History
621 lines (468 loc) · 17 KB

Retrofit.md

File metadata and controls

621 lines (468 loc) · 17 KB

Retrofit

简单来说 Retrofit 就是一个高级的 OKHttp

Retrofit 是一种在 Android 和 Java 应用程序中处理 HTTP 客户端的类型安全的库。这是由 Square, Inc. 开发的。Retrofit 被设计成简洁和高效,特别适合用于移动应用。通过 Retrofit,开发者可以很容易地将 HTTP API 转换成 Java 接口。

主要特点:

  1. 类型安全:Retrofit 使用注解来描述 HTTP 请求参数、路径和查询参数,这使得库能够确保类型的安全性。
  2. 高性能:Retrofit 基于 OkHttp 库,因此它继承了 OkHttp 的性能优势,如连接池、缓存和 HTTP/2 支持。
  3. 灵活性:Retrofit 支持同步和异步调用,允许开发者根据需要选择。
  4. 支持多种数据格式:Retrofit 支持多种数据格式,如 JSON、XML,以及 Protocol Buffers。
  5. 简洁的 API:Retrofit 提供了一种简洁、直观的 API,使得创建和管理网络请求变得简单。

一个实战的案例

我们现在是想,通过 Retrofit 访问一个天气的服务器,然后拿到一个地区的,温度的信息

首先要非常的感谢,有能够让我们随便访问的服务器

openweathermap注册的地址

现在你在这个网站当中注册一个账号

注册成功之后,就能够获得一个 APIKEY ,你也可以使用我的这里的现成的 key [ 544a1d9a2925e59467b8c59d1f59c29f ]

openweathermap的API响应格式

通过上面的这个文档我们知道以下的内容

请求的格式

https://api.openweathermap.org/data/2.5/weather?lat={lat}&lon={lon}&appid={API key}

也就是说,我们想要一个,天气的信息,那么我就需要,发送一个坐标(经度和维度),还有就是 key ,这个 key 就是前面,我们注册的时候,网站送给我们的 key

响应的格式

这个是官方告诉我们,他们大概会按照专业的形式,下发数据

{
  "coord": {
    "lon": 10.99,
    "lat": 44.34
  },
  "weather": [
    {
      "id": 501,
      "main": "Rain",
      "description": "moderate rain",
      "icon": "10d"
    }
  ],
  "base": "stations",
  "main": {
    "temp": 298.48,
    "feels_like": 298.74,
    "temp_min": 297.56,
    "temp_max": 300.05,
    "pressure": 1015,
    "humidity": 64,
    "sea_level": 1015,
    "grnd_level": 933
  },
  "visibility": 10000,
  "wind": {
    "speed": 0.62,
    "deg": 349,
    "gust": 1.18
  },
  "rain": {
    "1h": 3.16
  },
  "clouds": {
    "all": 100
  },
  "dt": 1661870592,
  "sys": {
    "type": 2,
    "id": 2075663,
    "country": "IT",
    "sunrise": 1661834187,
    "sunset": 1661882248
  },
  "timezone": 7200,
  "id": 3163858,
  "name": "Zocca",
  "cod": 200
}                        

开始写代码

了解了上面的信息之后,我们开始写代码

最开始,你应该添加依赖

    implementation 'com.squareup.retrofit2:retrofit:2.9.0'
    implementation 'com.squareup.retrofit2:converter-gson:2.9.0'

WeatherResponse

这个主要就是根据,服务器的下发数据,进行编写,所谓是一个萝卜一个坑,如果这个部分不是很理解的,我也不知道怎么解释,大概的意思就是,你需要,写一个类,来对应下发的 JSON 的数据,这里的嵌套就是通过,静态的内部类实现的,这里的嵌套的深度是,两层,如果你还有更加深度的掐套,那么,就需要,在静态内部类当中再加上一个静态的内部类,我相信,你懂我的意思,我也会在后面,提供一个案例

package com.open.OPENretrofit2;

import java.util.List;

public class WeatherResponse {
    public Coord coord;
    public List<Weather> weather;
    public String base;
    public Main main;
    public int visibility;
    public Wind wind;
    public Rain rain;
    public Clouds clouds;
    public long dt;
    public Sys sys;
    public int timezone;
    public int id;
    public String name;
    public int cod;

    public static class Coord {
        public double lon;
        public double lat;
    }

    public static class Weather {
        public int id;
        public String main;
        public String description;
        public String icon;
    }

    public static class Main {
        public float temp;
        public float feels_like;
        public float temp_min;
        public float temp_max;
        public int pressure;
        public int humidity;
        public int sea_level;
        public int grnd_level;
    }

    public static class Wind {
        public float speed;
        public int deg;
        public float gust;
    }

    public static class Rain {
        public float _1h;
    }

    public static class Clouds {
        public int all;
    }

    public static class Sys {
        public int type;
        public int id;
        public String country;
        public long sunrise;
        public long sunset;
    }
}

{
  "coord": {
    "lon": 10.99,
    "lat": 44.34
  },
  "weather": [
    {
      "id": 501,
      "main": "Rain",
      "description": "moderate rain",
      "icon": "10d"
    }
  ],
  "base": "stations",
  "main": {
    "temp": 298.48,
    "feels_like": 298.74,
    "temp_min": 297.56,
    "temp_max": 300.05,
    "pressure": 1015,
    "humidity": 64,
    "sea_level": 1015,
    "grnd_level": 933
  },
  "visibility": 10000,
  "wind": {
    "speed": 0.62,
    "deg": 349,
    "gust": 1.18
  },
  "rain": {
    "1h": 3.16
  },
  "clouds": {
    "all": 100
  },
  "dt": 1661870592,
  "sys": {
    "type": 2,
    "id": 2075663,
    "country": "IT",
    "sunrise": 1661834187,
    "sunset": 1661882248
  },
  "timezone": 7200,
  "id": 3163858,
  "name": "Zocca",
  "cod": 200
}                        

如果有更加深的JSON

JSON

{
  "outer": {
    "inner": {
      "field": "value"
    }
  }
}

Java

public class Response {
    public Outer outer;
    
    public static class Outer {
        public Inner inner;
        
        public static class Inner {
            public String field;
        }
    }
}

编写接口 OpenWeatherMapApi
import retrofit2.Call;
import retrofit2.http.GET;
import retrofit2.http.Query;

public interface OpenWeatherMapApi {
    @GET("weather")
    Call<WeatherResponse> getCurrentWeatherData(@Query("lat") String lat, @Query("lon") String lon, @Query("appid") String appid);
}

这里就是相当于在设置,请求头和设置 URL

@GET("weather")

@GET这个部分的作用是,将这个请求设置为 GET 类型

"weather" 表示的是 API 请求的相对 URL 路径

所谓的相当路径,就是相比较于我们之前说的,基础路径

这是我们之前看到的,URL

https://api.openweathermap.org/data/2.5/weather?lat={lat}&lon={lon}&appid={API key}

这个就是基础路径(怎么设置基础路径后面介绍)

https://api.openweathermap.org/data/2.5

后面的 weather 就是相对的路径(相对路径是放在最后的)

https://api.openweathermap.org/data/2.5/weather

Call<WeatherResponse> getCurrentWeatherData(@Query("lat") String lat, @Query("lon") String lon, @Query("appid") String appid);
}

这是一个 Retrofit 接口方法,它定义了一个 HTTP GET 请求,用于从 OpenWeatherMap API 获取当前天气数据

方法返回类型: Call<WeatherResponse>

  • Call<T>:这是 Retrofit 的一个类,代表一个尚未执行的 HTTP 请求。你可以通过这个 Call 对象来执行请求。
  • WeatherResponse:这是一个 Java 类,用于存储 API 响应的数据。Retrofit 将会把 HTTP 响应自动转换为这个类的一个对象。

方法名: getCurrentWeatherData

这是你为这个方法定义的名字。你将通过这个名字来调用这个方法。

方法参数: @Query("lat") String lat, @Query("lon") String lon, @Query("appid") String appid

这些是你在调用此方法时需要传递的参数。每个参数前都有一个 @Query 注解,这表示这些参数将会被添加到请求的 URL 中作为查询参数。

  • @Query("lat") String lat:这将会把传递的 lat 参数值添加到 URL 中,形成一个查询参数,例如:...?lat=value.
  • @Query("lon") String lon@Query("appid") String appid 同理。

当我们调用的时候(怎么调用,我们后面介绍)

call = apiInterface.getCurrentWeatherData("35.6895", "139.6917", "YOUR_API_KEY");

就会得到这样的 URL

GET http://api.openweathermap.org/data/2.5/weather?lat=35.6895&lon=139.6917&appid=YOUR_API_KEY

发起请求

这是一个点击一个按钮就能够发送一个请求,并且处理一个响应的一个函数,将获取到的响应当中的温度打印在,日志当中

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

import com.open.OPENretrofit2.databinding.ActivityMainBinding;

import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;

public class MainActivity extends AppCompatActivity {
    private Button buttonLoad;

    // Used to load the 'OPENretrofit2' library on application startup.
    static {
        System.loadLibrary("OPENretrofit2");
    }

    private ActivityMainBinding binding;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        binding = ActivityMainBinding.inflate(getLayoutInflater());
        setContentView(binding.getRoot());

        // Example of a call to a native method
        TextView tv = binding.sampleText;
        tv.setText(stringFromJNI());

        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("https://api.openweathermap.org/data/2.5/")
                .addConverterFactory(GsonConverterFactory.create())
                .build();

        OpenWeatherMapApi api = retrofit.create(OpenWeatherMapApi.class);


        buttonLoad = findViewById(R.id.buttonLoad);

        buttonLoad.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // 在这里发起网络请求
                Call<WeatherResponse> call = api.getCurrentWeatherData("35.6895", "139.6917", "544a1d9a2925e59467b8c59d1f59c29f");
                call.enqueue(new Callback<WeatherResponse>() {
                    @Override
                    public void onResponse(Call<WeatherResponse> call, Response<WeatherResponse> response) {
                        float temperature = response.body().main.temp;
                        Log.i("天气", "Temperature: " + temperature); // 在这里打印温度
                        Log.i("天气","获取成功");
                    }

                    @Override
                    public void onFailure(Call<WeatherResponse> call, Throwable t) {
                        // 处理错误
                        Log.i("天气","获取失败");
                    }
                });
            }
        });
    }

    /**
     * A native method that is implemented by the 'OPENretrofit2' native library,
     * which is packaged with this application.
     */
    public native String stringFromJNI();
}
请求的主体
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("https://api.openweathermap.org/data/2.5/")
                .addConverterFactory(GsonConverterFactory.create())
                .build();

        OpenWeatherMapApi api = retrofit.create(OpenWeatherMapApi.class);


                // 在这里发起网络请求
                Call<WeatherResponse> call = api.getCurrentWeatherData("35.6895", "139.6917", "544a1d9a2925e59467b8c59d1f59c29f");
                call.enqueue(new Callback<WeatherResponse>() {
                    @Override
                    public void onResponse(Call<WeatherResponse> call, Response<WeatherResponse> response) {
                        float temperature = response.body().main.temp;
                        Log.i("天气", "Temperature: " + temperature); // 在这里打印温度
                        Log.i("天气","获取成功");
                    }

                    @Override
                    public void onFailure(Call<WeatherResponse> call, Throwable t) {
                        // 处理错误
                        Log.i("天气","获取失败");
                    }
                });

创建 Retrofit Builder

        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("https://api.openweathermap.org/data/2.5/")
                .addConverterFactory(GsonConverterFactory.create())
                .build();

设置基础 URL

baseUrl("https://api.openweathermap.org/data/2.5/")

添加转换工厂

addConverterFactory(GsonConverterFactory.create())

这个工厂负责将 HTTP 响应体转换成 Java 对象,以及将 Java 对象转换成请求体

GsonConverterFactory.create() 使用 Gson 库来解析 JSON 响应

        OpenWeatherMapApi api = retrofit.create(OpenWeatherMapApi.class);


                // 在这里发起网络请求
                Call<WeatherResponse> call = api.getCurrentWeatherData("35.6895", "139.6917", "544a1d9a2925e59467b8c59d1f59c29f");
                call.enqueue(new Callback<WeatherResponse>() {
                    @Override
                    public void onResponse(Call<WeatherResponse> call, Response<WeatherResponse> response) {
                        float temperature = response.body().main.temp;
                        Log.i("天气", "Temperature: " + temperature); // 在这里打印温度
                        Log.i("天气","获取成功");
                    }

                    @Override
                    public void onFailure(Call<WeatherResponse> call, Throwable t) {
                        // 处理错误
                        Log.i("天气","获取失败");
                    }

OpenWeatherMapApi api = retrofit.create(OpenWeatherMapApi.class);

创建一个 OpenWeatherMapApi 接口的实例,该实例能够发起符合该接口描述的网络请求。Retrofit 会动态地为这个接口创建一个实现,这个实现会根据你在接口中定义的方法和注解来发起实际的 HTTP 请求。

Call<WeatherResponse> call = api.getCurrentWeatherData("35.6895", "139.6917", "544a1d9a2925e59467b8c59d1f59c29f");
                call.enqueue(new Callback<WeatherResponse>() {
                    @Override
                    public void onResponse(Call<WeatherResponse> call, Response<WeatherResponse> response) {
                        float temperature = response.body().main.temp;
                        Log.i("天气", "Temperature: " + temperature); // 在这里打印温度
                        Log.i("天气","获取成功");
                    }

                    @Override
                    public void onFailure(Call<WeatherResponse> call, Throwable t) {
                        // 处理错误
                        Log.i("天气","获取失败");
                    }

Call<WeatherResponse> call = api.getCurrentWeatherData("35.6895", "139.6917", "544a1d9a2925e59467b8c59d1f59c29f");

通过之前创建的 OpenWeatherMapApi 接口的实例 api,调用了 getCurrentWeatherData 方法,传入了经纬度和 API 密钥,创建了一个 Call<WeatherResponse> 对象,代表了一个还未执行的 HTTP 请求。

call.enqueue(new Callback<WeatherResponse>() {...});

这行代码通过调用 Call 对象的 enqueue 方法来异步执行前面创建的 HTTP 请求。enqueue 方法需要一个 Callback<WeatherResponse> 参数,该回调将在请求成功或失败时被触发。

public void onResponse(Call<WeatherResponse> call, Response<WeatherResponse> response) {
    float temperature = response.body().main.temp;
    Log.i("天气", "Temperature: " + temperature);
    Log.i("天气","获取成功");
}

处理成功的响应

public void onFailure(Call<WeatherResponse> call, Throwable t) {
    Log.i("天气","获取失败");
}

处理失败的响应