Retrofix2使用详解
来源:互联网 发布:单例设计模式php 编辑:程序博客网 时间:2024/06/11 02:16
简介
A type-safe HTTP client for Android and Java,一种类型安全的Http联网构架。
出品公司Square,项目地址。
项目导入
compile 'com.squareup.retrofit2:retrofit:2.2.0'
需android 2.3以上
网络请求步骤
1.创建一个接口,设置请求的类型与参数
接口中创建一个方法,返回一个Call对象,泛型是网络请求返回的数据转换成实体类对象集合,用注解来确定请求是GET还是POST
public interface GitHubService { @GET("users/{user}/repos") Call<List<Repo>> listRepos(@Path("user") String user);}
2.创建一个Retrofix对象
baseUrl()方法一般放置地址的主体部分,以/结尾
Retrofit retrofit = new Retrofit.Builder() .baseUrl("https://api.github.com/") .build();
3.生成一个接口实现对象
调用retrofit的create方法,传入第一步创建的请求接口,生成一个请求接口的实现对象
GitHubService service = retrofit.create(GitHubService.class);
4.生成一个Call实例对象
调用请求接口的对象方法可以生成一个Call对象实例,到这一步就可以得到最后的请求地址了。
Call<List<Repo>> repos = service.listRepos("octocat");
这是一个Get请求,传的是Path的参数,所以最后的请求地址拼接起来就是https://api.github.com/users/octocat/repos
5.发送请求
调用Call实例对象的方法就可以发送联网请求了,有两种方式,一种是同步请求,一种是异步请求。
同步请求
调用execute()方法,需要捕捉异常,返回结果的响应体,泛型为接口类中定义方法里返回类的泛型一样
try { Response<List<Repo>> response= repos.execute(); } catch (IOException e) { e.printStackTrace(); }
该方法源码解释
/** * Synchronously send the request and return its response. * * @throws IOException if a problem occurred talking to the server. * @throws RuntimeException (and subclasses) if an unexpected error occurs creating the request * or decoding the response. */ Response<T> execute() throws IOException;
异步请求
调用enqueue()方法,参数是一个回调,实现两个方法,一是请求成功调用的onResponse,可以得到响应体;二是请求失败调用的onFailure,可以查看异常。
repos.enqueue(new Callback<List<Repo>>() { @Override public void onResponse(Call<List<Repo>> call, Response<List<Repo>> response) { //调用响应的body()方法,即可得到返回的数据 List<Repo> repoList=response.body(); } @Override public void onFailure(Call<String> call, Throwable t) { //t即是异常类,可以打印异常信息 t.printStackTrace(); } });
该方法源码解释
/** * Asynchronously send the request and notify {@code callback} of its response or if an error * occurred talking to the server, creating the request, or processing the response. */ void enqueue(Callback<T> callback);
6.添加返回数据自动转换功能
上述第五步中有一句关键代码,实现了返回数据自动转换成实体类集合的过程,简单快捷。
List<Repo> repoList=response.body();
要实现该功能,有两步。
第一,添加Gson依赖,注意对应当前Retrofix版本
com.squareup.retrofit2:converter-gson:2.2.0
第二,构建Retrofix时,加上这句关键代码
Retrofit retrofit = new Retrofit.Builder() .baseUrl("https://api.github.com") //关键代码,添加转换工厂 .addConverterFactory(GsonConverterFactory.create()) .build();
也可以添加其它转换工厂,注意要在后面加上:2.2.0,当前的版本号
- Gson: com.squareup.retrofit2:converter-gson
- Jackson: com.squareup.retrofit2:converter-jackson
- Moshi: com.squareup.retrofit2:converter-moshi
- Protobuf: com.squareup.retrofit2:converter-protobuf
- Wire: com.squareup.retrofit2:converter-wire
- Simple XML: com.squareup.retrofit2:converter-simplexml
- Scalars (primitives, boxed, and String): com.squareup.retrofit2:converter-scalars //String类型的支持
所有请求方式的注解及参数类型关键字
retrofix内置有五个请求方式注解 GET, POST, PUT, DELETE, and HEAD.
其中GET请求与POST请求是Http经常使用的.
GET & POST请求方式传参数
以GET为例进行说明
@GET("group/{id}/users")Call<List<User>> groupList(@Path("id") int groupId, @Query("sort") String sort);
参数说明:
@Path:请求URL的字符替代,将网址中的{id}替换成自己传递的id
@Query:要传递的参数
如Call方法为:groupList(“9527”,”order by age desc”);
则最后发送的请求网址为: https://api.github.com/group/9527/users?sort=order by age desc
注意@Path只能用于地址的通配,如要传参数必须用@Query
传递多个参数
要实现的请求地址如下: https://api.github.com/group/9527/users?name=android&sort=order by age desc
方法1:添加多个@Query注解的参数
@GET("group/{id}/users")Call<List<User>> groupList(@Path("id") int groupId, @Query("name") String name);@Query("sort") String sort);
方法2:添加一个@QueryMap注解参数,里面包含多个@Query注解的参数
@GET("group/{id}/users")Call<List<User>> groupList(@Path("id") int groupId, @QueryMap Map<String, String> options);Map<String,String> options=new HashMap();options.put("name","android");options.put("sort","order by age desc");Call call=service.groupList("9527",options);
另也可以用同一个key值来传递多个数据
Map<String,List<String>> options=new HashMap();list.add("android");list.add("IOS");options.put("name",list);
得到的URL地址为
https://api.github.com/group/9527/users?name=android&name=IOS&sort=order by age desc
方法3:用@Body直接添加一个实体类对象,只适用于POST方式
@POST("users/new")Call<User> createUser(@Body User user);
Form-encoded(URL编码)
可以指定http请求URL编码,application/x-www-form-urlencoded,传递表单数据是键值对形式,适用于POST请求方式
@FormUrlEncoded@POST("user/edit")Call<User> updateUser(@Field("first_name") String first, @Field("last_name") String last);
在带有@FormURLEncode的POST请求中,只能用@Filed来传递参数,用法与@Query一致.
上传文件
指定编码方式为@Multipart,即是multipart/form-data,只有这种编码格式才可上传文件,可以用@PUT,也可以用@POST方式,参数只能用@Part注解
@Multipart@PUT("user/photo")Call<User> updateUser(@Part("photo") RequestBody photo, @Part("description") RequestBody description);
添加表头@Headers
//单项表头@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);//动态表头@GET("user")Call<User> getUser(@Header("Authorization") String authorization)
用retrofix2实现网络请求案例
1.构建一个小型服务器
使用eclipse创建一个web server项目HttpRequestDemo,然后创建一个继承HttpServlet的实现类。
这是一个用户登录的验证服务,正确的用户名qq123456,密码666666,返回一个json字符串。
这里处理的是GET请求,post请求用的也是一模一样的代码。
public class WebServerDemo extends HttpServlet { private static final long serialVersionUID = 29328731L; public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String name =request.getParameter("name"); String password=request.getParameter("pwd"); String result=""; String msg=""; if(!"qq123456".equalsIgnoreCase(name)){ result="fail"; msg="user name is fail"; }else{ if(!"666666".equals(password)){ result="fail"; msg="password is fail"; }else{ result="success"; msg="mession success"; } } String returnJson="{\"result\":\""+result+"\",\"msg\":\""+msg+"\"}"; response.setContentType("text/html"); PrintWriter out = response.getWriter(); out.println("<HTML>"); out.println(" <HEAD><TITLE>login page</TITLE></HEAD>"); out.println(" <BODY>"); out.println(returnJson); out.println(" </BODY>"); out.println("</HTML>"); out.flush(); out.close(); }}
在WebRoot/WEB_INF/web.xml里配置servlet与外部访问的路径地址
<?xml version="1.0" encoding="UTF-8"?>.... <!--配置servlet对应的类名与路径名 --> <servlet> <servlet-name>WebServerDemo</servlet-name> <servlet-class>server.WebServerDemo</servlet-class> </servlet> <!--将servlet与web对应 --> <servlet-mapping> <servlet-name>WebServerDemo</servlet-name> <!--/login即是外部访问的路径--> <url-pattern>/login</url-pattern> </servlet-mapping> .....</web-app>
最后将HttpRequestDemo部署至Tomcat中即可完成这个用户登录验证的小型服务器。 下载地址
2.发送登录请求
首先创建一个as自带的loginactivity登录界面,然后简化一些代码,减少登录过程中的一些验证。
然后运用上文步骤来发送联网请求。
public interface LoginService { @GET("{filepath}/login") Call<String> login4Path(@Path("filepath") String filepath); }
//注意这里的baseUrl是本机的IP地址,端口是tomcat默认的8080//这里并没有添加任何转换器mRetrofit=new Retrofit.Builder() .baseUrl("http://192.168.0.199:8080/") .build();
Call<String> call=mRetrofit.create(LoginService.class).login4Path("HttpRequestDemo"); call.enqueue(new Callback<String>() { @Override public void onResponse(Call<String> call, Response<String> response) { String resultStr=response.body(); mResultTextView.setText(resultStr); showProgress(false); if(resultStr.contains("fail")){ mPasswordView.requestFocus(); Toast.makeText(getApplicationContext(),"登录失败",Toast.LENGTH_SHORT).show(); }else if(resultStr.contains("success")){ startActivity(new Intent(RetrofixDemoActivity.this,LitepalDemoActivity.class)); } } @Override public void onFailure(Call<String> call, Throwable t) { t.printStackTrace(); } });
点击登录按钮,程序崩溃,一直报如下异常,无法创建一个转换器,LoginService.login4Path这个方法的结果无法转换成String.
java.lang.IllegalArgumentException: Unable to create converter for class java.lang.String for method LoginService.login4Path at retrofit2.ServiceMethod$Builder.methodError(ServiceMethod.java:751) at retrofit2.ServiceMethod$Builder.createResponseConverter(ServiceMethod.java:737) at retrofit2.ServiceMethod$Builder.build(ServiceMethod.java:168) at retrofit2.Retrofit.loadServiceMethod(Retrofit.java:169) at retrofit2.Retrofit$1.invoke(Retrofit.java:146) at $Proxy0.login4Path(Native Method)
这个错误的原因在于如果构建时retrofix实例时没有添加转换器,则Call对象的泛型只能使用RequestBody,这是比较容易忽略的异常。
将所有Call里的泛型换成RequestBody类,然后再运行程序,登录成功会跳转至另一个界面。
Call<ResponseBody> call=service.login4Path("HttpRequestDemo"); call.enqueue(new Callback<ResponseBody>() { @Override public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) { ResponseBody body=response.body(); String resultStr= ""; try { resultStr = body.string(); } catch (IOException e) { e.printStackTrace(); }......
这里不管输入什么都是返回用户名错误,因为这个请求并没有传参数,只是简单地返回了用户名不相同时的result与msg.
用一个Textview来显示服务器返回的所有数据。
3.用Post方式进行请求
public interface LoginService { @POST("{filepath}/login") Call<ResponseBody> login4Path(@Path("filepath") String filePath, @Query("name")String name, @Query("pwd")String pwd); }
String email = mEmailView.getText().toString(); String password = mPasswordView.getText().toString(); LoginService service=mRetrofit.create(LoginService.class); Call<ResponseBody>call= service.login4Path("HttpRequestDemo",email,password); call.enqueue(new Callback<ResponseBody>() {...}
运行结果:
demo地址
- Retrofix2使用详解
- Rxjava Retrofix2 okhttp3网络框架自解
- pdf详解 iTextSharp 使用详解
- 【Git使用详解】EGit使用详解
- POI使用详解 Apache POI使用详解
- function对象使用使用详解
- CheckStyle使用详解
- VSS使用详解释
- JDom使用详解
- JCoverage使用详解
- 正则表达式使用详解
- showModalDialog(),showModelessDialog()使用详解
- Ghost 使用详解
- SSI使用详解
- GDB使用详解
- SSI使用详解
- SSI使用详解1
- 正则表达式使用详解
- Leetcode--19. Remove Nth Node From End of List
- Python笔记-IO同步和异步、 读写文件、StringIO和BytesIO
- android:padding和android:layout_margin的区别?
- Java之I/O流
- 如何在EditText中设置固定图片——Android移动开发 .
- Retrofix2使用详解
- 关于表单数据的传输问题
- 我的java入门
- 12.python开源——pytest自动化测试框架
- FCFS和SJF进程调度算法的实现
- 简单实现网页登录框中的“记住我”
- Mybatis与Hibernate的区别
- 第八届蓝桥杯B组C/C++
- C#138课的主要内容