关于Retrofit,这个应该不是一个很新颖的东西了,简单过一下吧
1.由Square公司开发,基于Type-safe的REST客户端。
2.使用注解来定义API接口,使得HTTP请求变得简洁且易于维护。
3.支持同步和异步请求,可与RxJava、Coroutines等响应式编程库结合使用,实现流畅的异步操作。
4.内置转换器(Gson、Moshi、Jackson等)便于JSON和其他数据格式的序列化与反序列化。
5.支持自定义拦截器,进行统一的请求头添加、错误处理、日志记录等。
6.集成了OkHttp作为底层HTTP客户端,受益于其高效的连接复用、缓存策略和灵活的配置选项。
Retrofit因其强大的功能、清晰的API设计和广泛的社区支持,通常被视为首选。
先简单看一下本文要实现的效果吧

下面就一步步实现它吧
本文使用的开发环境:
Android Studio Iguana | 2023.2.1 Patch 1
gradle-8.4-bin.zip
本文所使用的天气预报API来源:
聚合数据(天气预报API可以免费调用)
接口地址:https://apis.juhe.cn/simpleWeather/query
APIKey还请自行申请
<uses-permission android:name="android.permission.INTERNET" />
- //retrofit
- implementation 'com.squareup.retrofit2:retrofit:2.9.0'
- implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
- /**
- * Constant 类用于存储应用程序中使用的常量。
- * 该类不包含任何方法,仅包含静态常量字段。
- */
- public class Constant {
- // 城市名称,示例为"长垣"
- public static final String CITY_NAME = "长垣";
- // 天气API的URL基础路径
- public static final String BASE_URL = "https://apis.juhe.cn";
- // 天气API的密钥,用于身份验证
- public static final String WEATHER_API_KEY = "你的APIKey";
- }
- /**
- * 天气服务接口,用于获取指定城市的天气信息。
- */
- public interface WeatherService {
- /**
- * 获取指定城市的天气信息。
- *
- * @param cityName 要查询天气的城市名称。
- * @param apiKey 用户的API密钥,用于身份验证。
- * @return Call
返回一个天气响应的Call对象,允许进行异步请求和响应处理。 - */
- @GET("/simpleWeather/query")
- Call
getWeather(@Query("city") String cityName, @Query("key") String apiKey); - }
这里需要说明一下
1.@GET表明是GET请求,后面括号内是具体的接口地址,比如我们前面的Constant中定义了BASE_URL,那么实际上getWeather请求的地址是BASE_URL拼接上我们给的/simpleWeather/query,这是请求天气数据的完整地址
2.(@Query("city") String cityName, @Query("key") String apiKey),这部分表明了GET请求后会拼接两个字段city和key,对应的值分别为cityName和apiKey,拼接的字段需要视具体的api而定
- /**
- * MVVM架构的应用程序类,提供全局的应用管理功能。
- */
- public class MVVMApplication extends Application {
-
- private static MVVMApplication instance;
- // 执行器服务,用于在后台线程中执行数据库操作或其他耗时操作
- public static final ExecutorService EXECUTOR_SERVICE = Executors.newSingleThreadExecutor();
-
- /**
- * 获取MVVMApplication的单例实例。
- *
- * @return MVVMApplication的全局唯一实例。
- */
- public static MVVMApplication getInstance() {
- return instance;
- }
-
- /**
- * 应用创建时调用的函数,用于初始化应用全局变量。
- */
- @Override
- public void onCreate() {
- super.onCreate();
- instance = this; // 初始化全局应用实例
- }
-
- // Retrofit实例,用于配置和创建网络请求
- private static Retrofit retrofit = new Retrofit.Builder()
- .baseUrl(WEATHER_API_URL) // 设置基础URL
- .addConverterFactory(GsonConverterFactory.create()) // 使用Gson进行数据转换
- .build();
-
- /**
- * 获取天气服务接口的实例,用于发起天气相关的网络请求。
- *
- * @return WeatherService接口的实例。
- */
- public static WeatherService getWeatherService() {
- return retrofit.create(WeatherService.class);
- }
- }
因为我们使用的是MVVM架构,那么调用接口的逻辑肯定是要放在ViewModel层的,如下
- /**
- * 天气视图模型类,用于处理与天气相关的数据逻辑。
- */
- public class WeatherViewModel extends ViewModel {
- // 存储天气数据的 LiveData 对象
- private MutableLiveData<WeatherResponse> weatherLiveData = new MutableLiveData<>();
- /**
- * 获取天气数据的 LiveData 对象。
- *
- * @return LiveData
天气数据的 LiveData 对象。 - */
- public LiveData<WeatherResponse> getWeatherLiveData() {
- return weatherLiveData;
- }
- // 存储错误代码的 LiveData 对象
- private MutableLiveData<Integer> errorCodeLiveData = new MutableLiveData<>();
- /**
- * 获取错误代码的 LiveData 对象。
- *
- * @return LiveData
错误代码的 LiveData 对象。 - */
- public LiveData<Integer> getErrorCodeLiveData() {
- return errorCodeLiveData;
- }
-
- /**
- * 根据提供的城市名和 API 密钥获取天气信息。
- *
- * @param city 要查询天气的城市名。
- * @param apiKey 用于查询天气的 API 密钥。
- */
- public void fetchWeather(String city, String apiKey) {
- WeatherService service = MVVMApplication.getWeatherService();
- Call<WeatherResponse> call = service.getWeather(city, apiKey);
- EXECUTOR_SERVICE.execute(() -> {
- call.enqueue(new Callback<WeatherResponse>() {
- @Override
- public void onResponse(Call<WeatherResponse> call, Response<WeatherResponse> response) {
- if (response.isSuccessful()) {
- // 成功获取天气数据时,更新 LiveData
- weatherLiveData.postValue(response.body());
- } else {
- // 获取天气数据失败时,发布错误代码
- errorCodeLiveData.postValue(response.code());
- }
- }
- @Override
- public void onFailure(Call<WeatherResponse> call, Throwable t) {
- // 请求天气数据失败时,发布错误代码
- errorCodeLiveData.postValue(-1);
- }
- });
- });
- }
-
- }
- /**
- * 天气活动类,用于展示和更新天气信息。
- */
- public class WeatherActivity extends AppCompatActivity {
-
- private ActivityWeatherBinding binding; // 数据绑定对象
- private WeatherViewModel viewModel; // 视图模型对象
-
- /**
- * 在活动创建时调用。
- *
- * @param savedInstanceState 如果活动之前被销毁,这参数包含之前的状态。如果活动没被销毁之前,这参数是null。
- */
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- EdgeToEdge.enable(this); // 启用边缘到边缘的UI
- // 设置数据绑定
- binding = DataBindingUtil.setContentView(this, R.layout.activity_weather);
-
- // 设置视图的内边距,以适应系统边框
- ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {
- Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
- v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
- return insets;
- });
-
- // 初始化视图模型
- viewModel = new ViewModelProvider(this).get(WeatherViewModel.class);
- binding.setViewModel(viewModel); // 将视图模型和绑定对象关联
- initObservers(); // 初始化观察者
-
- // 设置获取天气信息的点击监听器
- binding.btnGetWeather.setOnClickListener(v -> {
- viewModel.fetchWeather(CITY_NAME, WEATHER_API_KEY); // 触发获取天气数据
- });
- }
-
- /**
- * 初始化观察者,用于监听视图模型中的数据变化并更新UI。
- */
- private void initObservers() {
- // 观察实时天气数据
- viewModel.getWeatherLiveData().observe(this, weatherResponse -> {
- if (weatherResponse != null && weatherResponse.getErrorCode() == 0) {
- // 处理成功的天气响应,更新UI
- Optional.ofNullable(weatherResponse.getResult())
- .map(WeatherResponse.Result::getRealtime)
- .ifPresent(realtime -> {
- StringBuilder stringBuilder = new StringBuilder("长垣实时天气:" + "\n");
- stringBuilder.append("天气:" + realtime.getInfo() + "\n");
- stringBuilder.append("温度:" + realtime.getTemperature() + "\n");
- stringBuilder.append("湿度:" + realtime.getHumidity() + "%" + "\n");
- stringBuilder.append("风向:" + realtime.getDirect() + "\n");
- stringBuilder.append("风力:" + realtime.getPower() + "\n");
- stringBuilder.append("空气质量:" + realtime.getAqi() + "分" + "\n");
- binding.tvWeather.setText(stringBuilder.toString());
- });
- } else {
- // 处理失败的天气响应,显示错误信息
- binding.tvWeather.setText("获取天气失败");
- }
- });
-
- // 观察错误码,用于进一步处理错误情况
- viewModel.getErrorCodeLiveData().observe(this, errorCode -> {
- if (errorCode != null) {
- // TODO: 根据错误码进行相应的错误处理
- Log.i("WeatherActivity", "Error Code: " + errorCode);
- }
- });
- }
- }
- <?xml version="1.0" encoding="utf-8"?>
- <layout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto"
- xmlns:tools="http://schemas.android.com/tools">
-
- <data>
- <variable
- name="viewModel"
- type="com.example.mvvmdemo.ui.weather.WeatherViewModel" />
- </data>
-
- <androidx.constraintlayout.widget.ConstraintLayout
- android:id="@+id/main"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- tools:context=".ui.weather.WeatherActivity">
-
- <TextView
- android:id="@+id/tv_weather"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="长垣实时天气:"
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toTopOf="parent" />
-
- <Button
- android:id="@+id/btn_get_weather"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginBottom="16dp"
- android:text="更新天气"
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintStart_toStartOf="parent" />
- </androidx.constraintlayout.widget.ConstraintLayout>
- </layout>
至此,对于以上获取天气预报的功能就完成了,相信大家也基本上对于Retrofit网络请求框架有了一定的了解,不过本文还没有结束,因为前面的网络请求只是GET的,还要有POST请求的范例,简单说明一下吧
- @POST("/simpleWeather/query")
- Call
getWeather(@Body WeatherRequest request); -
- // WeatherRequest 类示例
- public class WeatherRequest {
- private String city;
- private String key;
-
- // 构造函数、getter、setter...
- }
当然,这只是举例说明POST请求的写法,实际上,大多数天气API通常使用GET方法来查询天气信息,因为这类操作通常是安全且幂等的,符合GET方法的语义。