Retrofit
适用于Android和Java的类型安全的HTTP客户端
声明API
接口方法及参数的注解用于控制一个请求.
请求方法
每一个方法必须带有一个HTTP注解, 用于提供相应的请求方法和URL. 目前有5种内置的注解: GET , POST , PUT , DELETE和
@GET("users/list")
您还可以指定URL中的查询参数.
@GET("users/list?sort=desc")
操作URL
请求URL可以使用方法中的替换块和参数进行动态替换. 替换块是指由 { 和 } 包裹的字符串. 其对应的参数必须使用相同的字符串,并使用
@GET("group/{id}/users")
Call<List<User>> groupList(@Path("id") int groupId);
查询参数同样可以动态添加.
@GET("group/{id}/users")
Call<List<User>> groupList(@Path("id") int groupId, @Query("sort") String sort);
对于复杂的查询参数组合, 可以使用
@GET("group/{id}/users")
Call<List<User>> groupList(@Path("id") int groupId, @QueryMap Map<String, String>
请求体
可以使用
@POST("users/new")
Call<User> createUser(@Body User user);
该对象同时也会被 Retrofit 实例所指定的转化器所转化. 如果没有添加转化器,则只有
编码表单和分段数据
方法也可以被声明为发送编码表单和分段数据.
当使用 @FormUrlEncoded 注解方法时, 则为发送编码表单数据.每个键值对使用
@FormUrlEncoded
@POST("user/edit")
Call<User> updateUser(@Field("first_name") String first, @Field("last_name")当使用 @Multipart 注解方法时, 则为分段请求.每段数据使用
@Multipart
@PUT("user/photo")
Call<User> updateUser(@Part("photo") RequestBody photo, @Part("description")分段数据需要使用 Retrofit 中的某个转化器,或者通过实现
操作请求头
您可以使用
@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);
注意, 请求头不会相互覆盖. 所有同名的请求头都会包含在请求中.
可以使用 @Header 注解来动态更新请求头.并且必须向 @Header 提供相应的参数. 如果参数值为空, 则该请求头将会被忽略. 如果参数值不为空,则会调用该值的
@GET("user")
Call<User> getUser(@Header("Authorization") String authorization)
对于所有请求都需要添加的请求头, 可以使用OkHttp interceptor来指定.
同步和异步
Call 实例既可以同步执行, 也可以异步执行. 每个实例只能被使用一次, 但通过调用
在Android中, 回调将会在主线程中执行. 在JVM中, 回调将发生在执行HTTP请求的线程中.
配置Retrofit
Retrofit 是一个将API接口转化为可调用对象的类. 默认情况下, Retrofit提供了默认的配置, 但他也允许进行自定义.
转化器
默认情况下, Retrofit只能将HTTP请求体反序列化为OkHttp的
并且在 @Body中只能接受
可以添加转化器以便支持其他类型. 为了您的使用便捷, 已经有6种模块适配了流行的序列化库.
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:converterscalars
以下是使用
的
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com")
.addConverterFactory(GsonConverterFactory.create())
.build();
GitHubService service = retrofit.create(GitHubService.class);
自定义转化器
如果您需要使用Retrofit不支持的内容格式(如YAML, txt, 自定义格式)与API进行通信, 或者您希望使用不同的库实现已有的格式, 您可以简单地创建自定义转化器.创建一个类继承
下载
Retrofit源码, 示例和网站可在GitHub上获取.
https://github.com/square/retrofit
依赖:
compile'com.squareup.retrofit2:retrofit:2.2.0'
混淆
如果您在项目中使用混淆, 请添加以下代码到混淆配置中:
-dontwarn retrofit2.**
-keep class retrofit2.** { *; }
-keepattributes Signature
-keepattributes Exceptions
做了个一个小案例先看一下App展示:
直接看代码:
public interface IService {
/**
* 每个方法必须有一个HTTP请求注释提供请求方法和相对URL。
* 有五个内置注释:GET、POST、PUT、DELETE、HEAD。
* 注解中指定资源的相对URL
* (说白了,就是除了Url根目录外的子目录,
* 比如:https://www.baidu.com/?tn=22073068_oem_dg
* 中,https://www.baidu.com为根目录,
* 后面的这一串:/?tn=22073068_oem_dg就是子目录,也就是需要在注解中写入的相对URL)。
*/
@GET("/test/test.json")
/**
* FruitData 为javabean对象
* getList(),该方法名字随便起
* @Query("title") String title 就是通过Query注解来查询title字段
*/
Call<FruitData> getList(@Query("title") String title);
}
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyHolder> {
private Context mContext;
private ArrayList<FruitData.FruitName> mDatas;
public MyAdapter(Context context, ArrayList<FruitData.FruitName> data) {
this.mContext = context;
this.mDatas = data;
}
@Override
public MyHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(mContext);
View view = inflater.inflate(R.layout.layout_recyclerview, parent, false);
MyHolder holder = new MyHolder(view);
return holder;
}
@Override
public void onBindViewHolder(MyHolder holder, int position) {
holder.tvTitle.setText(mDatas.get(position).title);
}
@Override
public int getItemCount() {
return mDatas.size();
}
class MyHolder extends RecyclerView.ViewHolder {
TextView tvTitle;
public MyHolder(View itemView) {
super(itemView);
tvTitle = (TextView) itemView.findViewById(R.id.tvTitle);
}
}
}
public class MainActivity extends AppCompatActivity {
private Button btnRetrofit;
private RecyclerView recyclerView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
}
private void initView() {
btnRetrofit = (Button) findViewById(R.id.btn_retrofit);
recyclerView = (RecyclerView) findViewById(R.id.recyclerview);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
btnRetrofit.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
useRetroift();
}
});
}
private void useRetroift() {
//获取Retrofit实例对象
Retrofit retrofit = new Retrofit.Builder()
//Url根目录
.baseUrl("http://192.168.1.101:8080")
//增减转换工厂(创建Gson转换工厂)
.addConverterFactory(GsonConverterFactory.create())
.build();
//获取接口对象
IService iService = retrofit.create(IService.class);
//获取Call对象
Call<FruitData> call = iService.getList("title");
//调用Call的异步网络请求方法
call.enqueue(new Callback<FruitData>() {
@Override
//请求成功,并获取到json解析后的数据
public void onResponse(Call<FruitData> call, Response<FruitData> response) {
ArrayList<FruitData.FruitName> data = response.body().data;
recyclerView.setAdapter(new MyAdapter(MainActivity.this, data));
}
@Override
public void onFailure(Call<FruitData> call, Throwable t) {
}
});
}
}
public class FruitData {
public ArrayList<FruitName> data;
public class FruitName {
public String title;
}
}