Android MVVM架构 + Retrofit完成网络请求

关于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版本:

        gradle-8.4-bin.zip 

本文所使用的天气预报API来源:

        聚合数据(天气预报API可以免费调用)

        接口地址:https://apis.juhe.cn/simpleWeather/query

        APIKey还请自行申请

 1.网络权限

<uses-permission android:name="android.permission.INTERNET" />

2.引用依赖

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

3.定义Constant文件

/*** 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";
}

4.编写天气服务接口

/*** 天气服务接口,用于获取指定城市的天气信息。*/
public interface WeatherService {/*** 获取指定城市的天气信息。** @param cityName 要查询天气的城市名称。* @param apiKey 用户的API密钥,用于身份验证。* @return Call<WeatherResponse> 返回一个天气响应的Call对象,允许进行异步请求和响应处理。*/@GET("/simpleWeather/query")Call<WeatherResponse> 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而定

5.Application中初始化Retrofit以及请求天气的接口

/*** 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;}/*** 应用创建时调用的函数,用于初始化应用全局变量。*/@Overridepublic 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层的,如下

6.ViewModel层代码

/*** 天气视图模型类,用于处理与天气相关的数据逻辑。*/
public class WeatherViewModel extends ViewModel {// 存储天气数据的 LiveData 对象private MutableLiveData<WeatherResponse> weatherLiveData = new MutableLiveData<>();/*** 获取天气数据的 LiveData 对象。** @return LiveData<WeatherResponse> 天气数据的 LiveData 对象。*/public LiveData<WeatherResponse> getWeatherLiveData() {return weatherLiveData;}// 存储错误代码的 LiveData 对象private MutableLiveData<Integer> errorCodeLiveData = new MutableLiveData<>();/*** 获取错误代码的 LiveData 对象。** @return LiveData<Integer> 错误代码的 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>() {@Overridepublic void onResponse(Call<WeatherResponse> call, Response<WeatherResponse> response) {if (response.isSuccessful()) {// 成功获取天气数据时,更新 LiveDataweatherLiveData.postValue(response.body());} else {// 获取天气数据失败时,发布错误代码errorCodeLiveData.postValue(response.code());}}@Overridepublic void onFailure(Call<WeatherResponse> call, Throwable t) {// 请求天气数据失败时,发布错误代码errorCodeLiveData.postValue(-1);}});});}}

7.Activity代码

/*** 天气活动类,用于展示和更新天气信息。*/
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) {// 处理成功的天气响应,更新UIOptional.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);}});}
}

8.布局文件

<?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><variablename="viewModel"type="com.example.mvvmdemo.ui.weather.WeatherViewModel" /></data><androidx.constraintlayout.widget.ConstraintLayoutandroid:id="@+id/main"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".ui.weather.WeatherActivity"><TextViewandroid: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" /><Buttonandroid: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<WeatherResponse> getWeather(@Body WeatherRequest request);// WeatherRequest 类示例
public class WeatherRequest {private String city;private String key;// 构造函数、getter、setter...
}

当然,这只是举例说明POST请求的写法,实际上,大多数天气API通常使用GET方法来查询天气信息,因为这类操作通常是安全且幂等的,符合GET方法的语义。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/3100.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【安卓13】解决带GMS编译报super分区空间不足错误

1、错误信息 2、解决方案 不同供应商修改分区大小的文件路径不一样&#xff0c;但是万变不离其宗&#xff0c;根据报错信息全局搜索关键词BOARD_SUPER_PARTITION_SIZE 这里以RK供应商和AML供应商修改为例&#xff1a; &#xff08;1&#xff09;RK改法&#xff1a; 根目录下…

全光谱灯对人体的危害?谨记全光谱灯选购要避开的四大套路

全光谱灯对人体的危害有多大&#xff1f;近年来网上关于护眼台灯对视力有害的言论有很多&#xff0c;引发了很多人空前的关注&#xff0c;事实上这未必是一件坏事&#xff0c;因为随着护眼台灯的热度持续上涨&#xff0c;市面上浑水摸鱼的行为增多了不少&#xff0c;有着不少劣…

STM32H7使用FileX库BUG,SD卡挂载失败

问题描述&#xff1a; 使用STM32H7ThreadXFileX&#xff0c;之前使用swissbit牌的存储卡可正常使用&#xff0c;最近项目用了金士顿的存储卡&#xff0c;发现无法挂载文件系统。 原因分析&#xff1a; 调试过程发现&#xff0c;关闭D-Cache可以挂载使用exfat文件系统。 File…

一文看够,植物线粒体基因组分析套路

线粒体堪称生命活动的“能量供给站”&#xff0c;植物线粒体是线粒体基因组研究中难度最高的&#xff0c;其基因组大小差异较大&#xff0c;100kb-10Mb&#xff0c;大部分由非编码DNA序列组成&#xff0c;且有许多同源序列&#xff0c;占基因组总长的2%-60%&#xff0c;基因间区…

制作github.io学术个人主页

制作如图的学术个人主页。About me - Xianwen Ling’s Blog 学术个人主页是一个学者展示个人学术成果和研究方向的重要工具。个人主页可以集中展示学者的研究论文、出版物、演讲和发布的项目等学术成果&#xff0c;这样其他人可以更方便地了解和评估学者的研究贡献。个人主页可…

Maven 安装及配置教程(Windows)【安装】

文章目录 一、 下载1. 官网下载2. 其它渠道 二、 安装三、 配置四、 验证五、 本地仓储配置六、 配置镜像七、 配置JDK八、完整配置九、常用命令十、IDEA 中配置 Maven1. 配置当前项目2. 配置新建 / 新打开 项目 软件 / 环境安装及配置目录 一、 下载 1. 官网下载 安装地址&a…

书生·浦语大模型第二期实战营第七节-OpenCompass 大模型评测实战 笔记和作业

来源&#xff1a; 视频教程&#xff1a;https://www.bilibili.com/video/BV1Pm41127jU/?spm_id_from333.788&vd_sourcef4a51f7f5a63e756f73ad0dff318c1a3 文字教程&#xff1a;https://github.com/InternLM/Tutorial/blob/camp2/opencompass/readme.md 作业来源&#x…

【Hadoop】- MapReduce YARN 初体验[9]

目录 提交MapReduce程序至YARN运行 1、提交wordcount示例程序 1.1、先准备words.txt文件上传到hdfs&#xff0c;文件内容如下&#xff1a; 1.2、在hdfs中创建两个文件夹&#xff0c;分别为/input、/output 1.3、将创建好的words.txt文件上传到hdfs中/input 1.4、提交MapR…

HotSpot JVM 中的应用程序/动态类数据共享

0.前言 本文的目的是详细讨论 HotSpot JVM 自 JDK 1.5 以来提供的一项功能&#xff0c;该功能可以减少启动时间&#xff0c;但如果在多个 JVM 之间共享相同的类数据共享 (CDS) 存档&#xff0c;则还可以减少内存占用。 1.类数据共享 (CDS) CDS 的想法是使用特定格式将预处理…

状态模式和策略模式对比

状态模式和策略模式都是行为型设计模式&#xff0c;它们的主要目标都是将变化的行为封装起来&#xff0c;使得程序更加灵活和可维护。之所以将状态模式和策略模式进行比较&#xff0c;主要是因为两个设计模式的类图相似度较高。但是&#xff0c;从状态模式和策略模式的应用场景…

Pulsar Meetup 深圳 2024 会务介绍

“ Hi&#xff0c;各位热爱 Pulsar 的小伙伴们&#xff0c;Pulsar Meetup 深圳 2024 报名倒计时啦&#xff0c;快来报名。这里汇集了腾讯、华为和谙流科技等大量 Pulsar 大咖&#xff0c;干货多多&#xff0c;礼品多多&#xff0c;不容错过啊。 ” 活动介绍 由 AscentStream 谙…

Python 0基础_变现_38岁_day 16(文件操作)

在python&#xff0c;使用内置函数open()进行文件的一些读写操作 文件操作格式&#xff1a;open(文件路径&#xff0c;访问模式&#xff0c;字符编码) 前面两个参数是必备参数&#xff0c;后面的字符编码为选填&#xff0c;但是大多数情况下都会协商字符编码 访问模式 r 只读 w…

数码摄影色彩构成,数码相机色彩管理

一、资料描述 本套摄影色彩资料&#xff0c;大小58.54M&#xff0c;共有6个文件。 二、资料目录 《抽象彩色摄影集》.阿瑟.pdf 《色彩构成》.pdf 《色彩学》.星云.扫描版.pdf 《摄影色彩构成》.pdf 《数码相机色彩管理》.pdf 数码摄影进阶之4《色彩篇》.pdf 三、资料下…

解决IDEA中Tomcat控制台乱码问题(包括sout输出乱码)

文章目录 前言一、控制台直接输出乱码二、sout输出内容在控制台显示乱码 前言 今天在使用Tomcat的时候发现控制台输入出现了乱码问题&#xff0c;其实之前就出现过一次&#xff0c;解决了&#xff0c;但是新创建一个项目后又会出现sout的内容在控制台输出的乱码问题&#xff0…

Windows下Git的使用

目录 一、克隆远程仓库到本地二、git的三板斧2.1 add-将代码添加到本地仓库2.2 commit-提交代码到本地仓库2.3 push-推送本次添加操作到远程仓库2.4 gitee只有三板斧吗&#xff1f; 三、推送后没有出现绿点四、push到远程时报错五、git图形化界面下载链接 一、克隆远程仓库到本…

sql题目练习

cookie注入 解题思路和之前的整数型注入一样&#xff0c;只是比整数型注入多了一步&#xff0c;题目没有给输入框&#xff0c;提示“尝试找找cookie吧”cookie的中文翻译是曲奇&#xff0c;小甜饼的意思。cookie其实就是一些数据信息&#xff0c;类型为“小型文本文件”&#…

【CSS】CSS实现元素逐渐消失(实现元素透明逐渐消失/模糊)

mask-image: linear-gradient(to bottom, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 1) 10%);mask-image 属性用于定义一个遮罩&#xff0c;它可以隐藏元素的一部分或全部内容。在这个示例中&#xff0c;我们使用 mask-image 属性来定义一个线性渐变的遮罩&#xff0c;使得列表项的内…

如何用微信发布考试成绩(如月考、期中、期末等)

自教育部《未成年人学校保护规定》颁布后,教育部明确表示:学校不得公开学生的考试成绩、排名等信息!同时学校应采取措施,便利家长知道学生的成绩等学业信息,对于教师来说,如何用微信发布考试成绩(如:月考、期中、期末等)就成了一道难题... 公开吧,会伤害到学生自尊心,甚至被投诉…

区块链 | OpenSea 相关论文:Toward Achieving Anonymous NFT Trading(三)

&#x1f951;原文&#xff1a; Toward Achieving Anonymous NFT Trading VII 讨论&#xff1a;关于匿名性与市场平台的困境 在本文的这一部分&#xff0c;我们将讨论关于隐藏 NFT 所有者地址的困境&#xff0c;以及为什么像 OpenSea 这样的 NFT 市场平台几乎必须得到完全的信…