Android--Retrofit浅入深出

2024-04-08 07:32
文章标签 android retrofit 浅入 深出

本文主要是介绍Android--Retrofit浅入深出,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

官网:http://square.github.io/retrofit/

官方定义:
A type-safe HTTP client for Android and Java

一:配置
app:build.gradle:

compile 'com.squareup.retrofit2:retrofit:2.0.2'

二:例子

–1:BaseResponse

public class BaseResponse {String returnCode;String msg;String result;boolean success;public String getReturnCode() {return returnCode;}public void setReturnCode(String returnCode) {this.returnCode = returnCode;}public String getMsg() {return msg;}public void setMsg(String msg) {this.msg = msg;}public String getResult() {return result;}public void setResult(String result) {this.result = result;}public boolean isSuccess() {return success;}public void setSuccess(boolean success) {this.success = success;}
}

–2:HtppService


public interface HttpService {@FormUrlEncoded@POST("/frist/noIntercept/user/login.do")Call<UserResponse> getUserByLogin(@Field("password") String password, @Field("phone") String phone);}

–3:User

public class User {private int id;private boolean invalid;private int status;private long createdDatetime;private long updatedDatetime;private int orderTag;private String name;private String phone;private String password;private String slogan;private String imagpath;private int userid;private int sex;public int getId() {return id;}public void setId(int id) {this.id = id;}public boolean isInvalid() {return invalid;}public void setInvalid(boolean invalid) {this.invalid = invalid;}public int getStatus() {return status;}public void setStatus(int status) {this.status = status;}public long getCreatedDatetime() {return createdDatetime;}public void setCreatedDatetime(long createdDatetime) {this.createdDatetime = createdDatetime;}public long getUpdatedDatetime() {return updatedDatetime;}public void setUpdatedDatetime(long updatedDatetime) {this.updatedDatetime = updatedDatetime;}public int getOrderTag() {return orderTag;}public void setOrderTag(int orderTag) {this.orderTag = orderTag;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getPhone() {return phone;}public void setPhone(String phone) {this.phone = phone;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}public String getSlogan() {return slogan;}public void setSlogan(String slogan) {this.slogan = slogan;}public String getImagpath() {return imagpath;}public void setImagpath(String imagpath) {this.imagpath = imagpath;}public int getUserid() {return userid;}public void setUserid(int userid) {this.userid = userid;}public int getSex() {return sex;}public void setSex(int sex) {this.sex = sex;}
}

–4:BaseResponse

public class UserResponse extends BaseResponse {private RespData data;public RespData getData() {return data;}public void setData(RespData data) {this.data = data;}public static class RespData {private User user;public User getUser() {return user;}public void setUser(User user) {this.user = user;}}
}

–5:MainActivity

public class MainActivity extends AppCompatActivity implements View.OnClickListener { 
private static final String WEB_URL = "http://192.168.1.115:8080";@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);findViewById(R.id.start).setOnClickListener(this);}@Overridepublic void onClick(View v) {switch (v.getId()) {case R.id.start:getUser();break;}}private void getUser() {Retrofit retrofit = new Retrofit.Builder().baseUrl(WEB_URL).addConverterFactory(GsonConverterFactory.create()).build();HttpService httpService = retrofit.create(HttpService.class);String phone = "15029206553";String password = "123456";Call<UserResponse> call = httpService.getUserByLogin(password, phone);call.enqueue(new Callback<UserResponse>() {@Overridepublic void onResponse(Call<UserResponse> call, Response<UserResponse> response) {Toast.makeText(MainActivity.this, "respone" + response.body().getData().getUser().getImagpath(), Toast.LENGTH_LONG).show();}@Overridepublic void onFailure(Call<UserResponse> call, Throwable t) {}});}
}

注:可以看出,接口返回的是需要的JAVA对象,不是而不是byte[]或String!Retrofit内部默认使用Gson解析相关数据。

三:相关方法:

—-1:支持:GET, POST, PUT, DELETE, and HEAD!

@GET("users/list")
@GET("/frist/noIntercept/user/login.do")
Call<UserResponse> getUserByLogin(@Query("password") String password, @Query("phone") String phone);

也可以直接在请求接口中显示需要的参数,类似于:

@GET("users/list?sort=desc")
@GET("/frist/noIntercept/user/login.do?password=123456&phone=15029206553")
Call<UserResponse> getUserByLogin();

使用技巧:当我们使用POST方式无参去请求数据的时候,请修改为无参的GET请求。
- - 2:可以动态更新请求块里面的参数和方法,一个相应的参数必须和@Path保持同样的字符串

 @GET("group/{id}/users")Call<List<User>> groupList(@Path("id") int groupId);
@GET("/frist/noIntercept/{user}/login.do?password=123456&phone=15029206553")
Call<UserResponse> getUserByLogin(@Path("user") String user);

也可以使用查询方法来添加相关参数,类似于:

 @GET("group/{id}/users")Call<List<User>> groupList(@Path("id") int groupId, @Query("sort") String sort);
@GET("/frist/noIntercept/{user}/login.do")
Call<UserResponse> getUserByLogin(@Path("user") String user,@Query("password") String password, @Query("phone") String phone);

—-3:Map使用

@GET("group/{id}/users")
Call<List<User>> groupList(@Path("id") int groupId, @QueryMap Map<String, String> options);

使用技巧:对于复杂参数,可以使用Map来组合请求对象。

—-4:JavaBean作为请求体<添加转换器,若没有添加,只能使用response>

@POST("users/new")Call<User> createUser(@Body User user);
public class LoginBean {String password;String phone;public  LoginBean(String password, String phone){this.password=password;this.phone=phone;}
}@POST("/frist/noIntercept/user/login.do")
Call<UserResponse> getUserByLogin(@Body LoginBean loginBean);
String phone = "15029206553";
String password = "123456";
LoginBean loginBean=new LoginBean(password,phone);
Call<UserResponse> call = httpService.getUserByLogin(loginBean);

注意点:使用此种方式传参,需要修改后台正常获取参数的方式,慎用。

—-5:指定请求编码类型

@FormUrlEncoded
@POST("user/edit")
Call<User> updateUser(@Field("first_name") String first, @Field("last_name") String last);
@FormUrlEncoded
@POST("/frist/noIntercept/user/login.do")
Call<UserResponse> getUserByLogin(@Field("password") String password, @Field("phone") String phone);

—-6:操作Head

@Headers("Cache-Control: max-age=640000")
@GET("widget/list")
Call<List<Widget>> widgetList();

也可以写成下面:

@Headers({"Accept: application/vnd.github.v3.full+json","User-Agent: Retrofit-Sample-App"})
@GET("users/{username}")
Call<User> getUser(@Path("username") String username);

注:当@Headers{}为空时,则会自动忽略。

—-7:每个请求都添加Head:<动态更新>

@GET("user")
Call<User> getUser(@Header("Authorization") String authorization)

—-8:使用ConverterFactory来修改默认返回数据解析<可自定义转换器>
Retrofit默认使用GSON进行相关数据解析。

这里写图片描述

下面是一个使用GsonConverterFactory生成JSON解析数据的例子:

Retrofit retrofit = new Retrofit.Builder().baseUrl("https://api.github.com").addConverterFactory(GsonConverterFactory.create()).build();
GitHubService service = retrofit.create(GitHubService.class);

四:简单封装:
–1:RetrofitUtil:

public class RetrofitUtil {private static final String WEB_URL = "http://192.168.1.115:8080";public static HttpService instanceHttpService() {Retrofit retrofit = new Retrofit.Builder().baseUrl(WEB_URL).addConverterFactory(GsonConverterFactory.create()).build();HttpService httpService = retrofit.create(HttpService.class);return httpService;}
}

–2:MainActivity:

public class MainActivity extends AppCompatActivity implements View.OnClickListener {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);findViewById(R.id.start).setOnClickListener(this);}@Overridepublic void onClick(View v) {switch (v.getId()) {case R.id.start:getUser();break;}}private void getUser() {String phone = "15029206553";String password = "123456";Call<UserResponse> call = RetrofitUtil.instanceHttpService().getUserByLogin(password, phone);call.enqueue(new Callback<UserResponse>() {@Overridepublic void onResponse(Call<UserResponse> call, Response<UserResponse> response) {Toast.makeText(MainActivity.this, "respone" + response.body().getData().getUser().getImagpath(), Toast.LENGTH_LONG).show();}@Overridepublic void onFailure(Call<UserResponse> call, Throwable t) {}});}
}

可以看出来:代码量减少很多。

五:深度封装:
拦截器是一个强大的机制,可以监视,重写,然后重新调用。
–1:
调用链的调用(请求)是每个拦截的执行的一个关键部分:

public class LoggingInterceptor implements Interceptor {@Overridepublic Response intercept(Chain chain) throws IOException {Request request = chain.request();long t1 = System.nanoTime();.....// request.url(), chain.connection(), request.headers();Response response = chain.proceed(request);long t2 = System.nanoTime();....// response.request().url(), (t2 - t1) / 1e6d, response.headers();return response;}
}

这里写图片描述

–2:Application interceptors:
—-:拦截器分为应用拦截和网络:
打印拦截器:

HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
logging.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient httpClient = new OkHttpClient.Builder().addInterceptor(logging)//添加打印拦截器.connectTimeout(30, TimeUnit.SECONDS)//设置请求超时时间.retryOnConnectionFailure(true)//设置出现错误进行重新连接。.build();
注意:多了一个.client()方法:
Retrofit retrofit = new Retrofit.Builder().baseUrl(WEB_URL).client(httpClient).addConverterFactory(GsonConverterFactory.create()).build();

因为OKHTTP支持重定向,而Retrofit是基于OKHTTP3建立各种模块的。

–3:重定向

OkHttpClient client = new OkHttpClient.Builder().addInterceptor(new LoggingInterceptor()).build();Request request = new Request.Builder().url("http://www.publicobject.com/helloworld.txt").header("User-Agent", "OkHttp Example").build();Response response = client.newCall(request).execute();
response.body().close();

结果为:

INFO: Sending request http://www.publicobject.com/helloworld.txt on null
User-Agent: OkHttp ExampleINFO: Received response for https://publicobject.com/helloworld.txt in 1179.7ms
Server: nginx/1.4.6 (Ubuntu)
Content-Type: text/plain
Content-Length: 1759
Connection: keep-alive

–4:网络监听器

.addNetworkInterceptor(new LoggingInterceptor())

应用和网络拦截器比对:

应用拦截器:
--1:不用担心请求时重定向和定向次数
--2:调用次数为一次<缓存>
--3:允许重试,多次调用请求链<okhttp请求是通过链路进行管理的>
--4:可以观察应用的意图,在请求或者返回数据的时候进行相关匹配以及处理
网络拦截器:
--1:观察数据传输

六:特殊需求:
–1:所有网络请求都添加token:

Interceptor mToken = new Interceptor() {@Overridepublic Response intercept(Chain chain) throws IOException {Request originalRequest = chain.request();if (You.token == null || alreadyHasAuthorizationHeader(originalRequest)) {return chain.proceed(originalRequest);}Request authorised = originalRequest.newBuilder().header("Authorization", You.token).build();return chain.proceed(authorised);}
};public static boolean alreadyHasAuthorizationHeader(Request request) {if (request != null) {if (request.headers() != null) {return true;} else {return false;}}return false;
}

–1:
—-:if判断,当你有token的时候才会进行添加,或者请求验证中已经有hrader了,那么就不执行这个token了。
—-:header 的 key 通常是 Authorization,可以修改

2–:添加公私密钥

MarvelSigningInterceptor signingInterceptor = new MarvelSigningInterceptor(KeyValue.MARVEL_PUBLIC_KEY, KeyValue.MARVEL_PRIVATE_KEY);

3–:添加缓存策略

File cacheFile = new File(context.getCacheDir(), "ZhiBookCache");Cache cache = new Cache(cacheFile, 1024 * 1024 * 50);Interceptor interceptorCache = new Interceptor() {@Overridepublic Response intercept(Chain chain) throws IOException {Request request = chain.request();if (!NetworkStateUtils.getInstance(context).isConnection()) {request = request.newBuilder().cacheControl(CacheControl.FORCE_CACHE).build();}Response response = chain.proceed(request);if (NetworkStateUtils.getInstance(context).isConnection()) {int maxAge = 0 * 60;// 有网络时 设置缓存超时时间0个小时response.newBuilder().header("Cache-Control", "public, max-age=" + maxAge).removeHeader("Pragma")// 清除头信息,因为服务器如果不支持,会返回一些干扰信息,不清除下面无法生效.build();} else {// 无网络时,设置超时为4周int maxStale = 60 * 60 * 24 * 28;response.newBuilder().header("Cache-Control", "public, only-if-cached, max-stale=" + maxStale).removeHeader("Pragma").build();}return response;}};

七:再次封装:
–1:

public abstract class RCllBack<T> implements Callback<T> {@Overridepublic void onResponse(Call<T> call, Response<T> response) {onSuccess(response.body());}@Overridepublic void onFailure(Call<T> call, Throwable t) {}public abstract void onSuccess(T response);
}

–2:

public abstract class RCllBaackComm<T> implements Callback<T> {@Overridepublic void onResponse(Call<T> call, Response<T> response) {BaseResponse resp = (BaseResponse) response.body();//在此可以根据自己的功能需求进行相关判断}@Overridepublic void onFailure(Call<T> call, Throwable t) {onFailed(new CommError("网络错误"));}public abstract void onSuccess(T response);public abstract void onFailed(CommError error);}

概念理解:

onResponse: HTTP有效也就是请求返回为200,返回数据
因此在此方法里面,可以根据自己和服务器返回值的约定进行相关处理;

onFailure:当请求地址不存在或者其他原因<无网络>

以下为三种不同方法用起来的差异:

Call<UserResponse> call = RetrofitUtil.service.getUserByLogin(password, phone);
//1
call.enqueue(new Callback<UserResponse>() {@Overridepublic void onResponse(Call<UserResponse> call, Response<UserResponse> response) {Toast.makeText(MainActivity.this, "respone" + response.body().getData().getUser().getImagpath(), Toast.LENGTH_LONG).show();}@Overridepublic void onFailure(Call<UserResponse> call, Throwable t) {}
});
//2
call.enqueue(new RCllBack<UserResponse>() {@Overridepublic void onSuccess(UserResponse response) {}
});
//3
call.enqueue(new RCllBaackComm<UserResponse>() {@Overridepublic void onSuccess(UserResponse response) {}@Overridepublic void onFailed(CommError error) {}
});

相关依赖引入:

compile 'com.squareup.retrofit2:retrofit:2.0.0-beta4'
compile 'com.squareup.retrofit2:converter-gson:2.0.0-beta4'
compile 'com.squareup.retrofit2:adapter-rxjava:2.0.0-beta4'
compile 'com.squareup.okhttp3:okhttp:3.0.1'
compile 'com.squareup.okhttp3:logging-interceptor:3.0.1'

本次源码获取地址:
github:https://github.com/erhutime/NetWorking

这篇关于Android--Retrofit浅入深出的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/884945

相关文章

Android实现任意版本设置默认的锁屏壁纸和桌面壁纸(两张壁纸可不一致)

客户有些需求需要设置默认壁纸和锁屏壁纸  在默认情况下 这两个壁纸是相同的  如果需要默认的锁屏壁纸和桌面壁纸不一样 需要额外修改 Android13实现 替换默认桌面壁纸: 将图片文件替换frameworks/base/core/res/res/drawable-nodpi/default_wallpaper.*  (注意不能是bmp格式) 替换默认锁屏壁纸: 将图片资源放入vendo

Android平台播放RTSP流的几种方案探究(VLC VS ExoPlayer VS SmartPlayer)

技术背景 好多开发者需要遴选Android平台RTSP直播播放器的时候,不知道如何选的好,本文针对常用的方案,做个大概的说明: 1. 使用VLC for Android VLC Media Player(VLC多媒体播放器),最初命名为VideoLAN客户端,是VideoLAN品牌产品,是VideoLAN计划的多媒体播放器。它支持众多音频与视频解码器及文件格式,并支持DVD影音光盘,VCD影

android-opencv-jni

//------------------start opencv--------------------@Override public void onResume(){ super.onResume(); //通过OpenCV引擎服务加载并初始化OpenCV类库,所谓OpenCV引擎服务即是 //OpenCV_2.4.3.2_Manager_2.4_*.apk程序包,存

从状态管理到性能优化:全面解析 Android Compose

文章目录 引言一、Android Compose基本概念1.1 什么是Android Compose?1.2 Compose的优势1.3 如何在项目中使用Compose 二、Compose中的状态管理2.1 状态管理的重要性2.2 Compose中的状态和数据流2.3 使用State和MutableState处理状态2.4 通过ViewModel进行状态管理 三、Compose中的列表和滚动

Android 10.0 mtk平板camera2横屏预览旋转90度横屏拍照图片旋转90度功能实现

1.前言 在10.0的系统rom定制化开发中,在进行一些平板等默认横屏的设备开发的过程中,需要在进入camera2的 时候,默认预览图像也是需要横屏显示的,在上一篇已经实现了横屏预览功能,然后发现横屏预览后,拍照保存的图片 依然是竖屏的,所以说同样需要将图片也保存为横屏图标了,所以就需要看下mtk的camera2的相关横屏保存图片功能, 如何实现实现横屏保存图片功能 如图所示: 2.mtk

android应用中res目录说明

Android应用的res目录是一个特殊的项目,该项目里存放了Android应用所用的全部资源,包括图片、字符串、颜色、尺寸、样式等,类似于web开发中的public目录,js、css、image、style。。。。 Android按照约定,将不同的资源放在不同的文件夹中,这样可以方便的让AAPT(即Android Asset Packaging Tool , 在SDK的build-tools目

Android fill_parent、match_parent、wrap_content三者的作用及区别

这三个属性都是用来适应视图的水平或者垂直大小,以视图的内容或尺寸为基础的布局,比精确的指定视图的范围更加方便。 1、fill_parent 设置一个视图的布局为fill_parent将强制性的使视图扩展至它父元素的大小 2、match_parent 和fill_parent一样,从字面上的意思match_parent更贴切一些,于是从2.2开始,两个属性都可以使用,但2.3版本以后的建议使

Android Environment 获取的路径问题

1. 以获取 /System 路径为例 /*** Return root of the "system" partition holding the core Android OS.* Always present and mounted read-only.*/public static @NonNull File getRootDirectory() {return DIR_ANDR

Android逆向(反调,脱壳,过ssl证书脚本)

文章目录 总结 基础Android基础工具 定位关键代码页面activity定位数据包参数定位堆栈追踪 编写反调脱壳好用的脚本过ssl证书校验抓包反调的脚本打印堆栈bilibili反调的脚本 总结 暑假做了两个月的Android逆向,记录一下自己学到的东西。对于app渗透有了一些思路。 这两个月主要做的是代码分析,对于分析完后的持久化等没有学习。主要是如何反编译源码,如何找到

android系统源码12 修改默认桌面壁纸--SRO方式

1、aosp12修改默认桌面壁纸 代码路径 :frameworks\base\core\res\res\drawable-nodpi 替换成自己的图片即可,不过需要覆盖所有目录下的图片。 由于是静态修改,则需要make一下,重新编译。 2、方法二Overlay方式 由于上述方法有很大缺点,修改多了之后容易遗忘自己修改哪些文件,为此我们采用另外一种方法,使用Overlay方式。