Retrofit2.0和Rxjava结合使用的简单记录
2017-07-26 00:55
483 查看
Gradle的配置(该配置是针对rxjava1.x的)
compile 'com.squareup.retrofit2:converter-gson:2.0.0-beta4' compile 'com.squareup.retrofit2:adapter-rxjava:2.0.0-beta4' //okhttp log 工具 compile 'com.squareup.okhttp3:logging-interceptor:3.1.2' compile 'com.google.code.gson:gson:2.5' compile 'io.reactivex:rxandroid:1.1.0' compile 'io.reactivex:rxjava:1.1.0' compile 'com.squareup.retrofit2:retrofit:2.0.0-beta4'
##常用的注解
@Path:该注解写在方法中的参数类型(String)前面;用于指定@POST()或者@GET()请求中括号中的参数;该参数中不允许存在 斜杠 , 即只能表示一级,类似"目录";
可以把所有的路径都存在一个类中,在@Post()的括号中引用这个路径,这样@Path就不需要使用;除非相同路径下都是最后一级不相同,可以使用该注解。
@ Url :该注解写在方法的参数类型前面;表示完整的Url。
@Query:用于自动拼接URL ?id=3&name=zhangsan&age=24;Post和Get请求中都可以使用
@QueryMap :传入一个Map类型,自动拼接URL;Post和Get请求中都可以使用
@FormUrlEncoded 和Post一起使用;提交没有文件的表单数据;和参数注解@Field和@FieldMap配合使用
@ Field:用于POST请求中,输入拼接的请求体键值对;不带文件上传的表单提交
@ FieldMap :用于POST请求中,输入拼接的请求体键值对的Map对象;不带文件上传的表单提交
@Streaming:下载文件必须要加上这个,保证下载的内容不会一下子都加载到内存中去;表示和服务器是长连接,会边下载流,边处理(比如写入存储器中),使得内存不会有一直持有所有的流数据。
@Multipart:提交带有文件的表单使用;配合参数注解@Part和@PartMap使用;@PartMap的类型是
<String,RequestBody>
@Part,@PartMap: 用于POST文件上传
@PartMap接受的数据类型是HashMap<String,RequestBody>
@Part用法:@Part("xxx") RequestBody body
@Body 如果上传的内容不是用@MultiPart来修饰的,也不是要传递键值对。参数中不能用@Part或者@PartMap来修饰。此时选择用@Body;比如传递一个json字符串给服务器,此时就需要body,还需要改一下Header
关于文件的上传:
参见 :/detail/2687595889.html
文件的下载可以使用 RxDownload
@Body:POST请求中的参数
@RequestBody
okhttp3.Media的常见type类型
eg: RequestBody.create(okhttp3.MediaType.parse("application/json; charset=utf-8"), jsonString);
text/html : HTML格式
text/plain :纯文本格式
text/xml : XML格式
image/gif :gif图片格式
image/jpeg :jpg图片格式
image/png:png图片格式
以application开头的媒体格式类型:
application/xhtml+xml :XHTML格式
application/xml : XML数据格式
application/atom+xml :Atom XML聚合格式
application/json : JSON数据格式
application/pdf :pdf格式
application/msword : Word文档格式
application/octet-stream : 二进制流数据(如常见的文件下载)
application/x-www-form-urlencoded : <form encType=””>中默认的encType,form表单数据被编码为key/value格式发送到服务器(表单默认的提交数据的格式)
另外一种常见的媒体格式是上传文件之时使用的:
multipart/form-data : 需要在表单中进行文件上传时,就需要使用该格式
@Headers :注解设置固定的请求头,所有请求头不会相互覆盖,即使名字相同。
@Headers("Cache-Control: max-age=640000") @GET("widget/list") Call<List<Widget>> widgetList(); // 注意Headers括号中的键值对,冒号后面有一个空格!!!! @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 注解动态更新请求头,匹配的参数必须提供给 @Header ,若参数值为 null ,这个头会被省略,否则,会使用参数值的 toString 方法的返回值。
@GET("user") Call<User> getUser(@Header("Authorization") String authorization)
获取Retrofit的实例
public class RetrofitClient { private static final String TAG = "RetrofitClient"; // private static final String BASE_URL ="https://api.douban.com/v2/movie/"; private static OkHttpClient client = new OkHttpClient.Builder() .addInterceptor(new Interceptor() { @Override public Response intercept(Chain chain) throws IOException { // Log.v(TAG,chain.connection().route().address().toString()); Log.v(TAG,chain.request().url().toString()); Request.Builder builder = chain.request().newBuilder(); //添加共同的头信息 // builder.addHeader("token", "abc"); return chain.proceed(builder.build()); } }) .connectTimeout(15, TimeUnit.SECONDS) .readTimeout(15, TimeUnit.SECONDS) .build(); private static class Holder{ private static Retrofit retrofit = new Retrofit.Builder() .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) .addConverterFactory(GsonConverterFactory.create()) .addConverterFactory(StringConverterFactory.create()) .baseUrl(UrlConst.BASE_URL) .client(client) .build(); } public static Retrofit getRetrofitInstance() { return Holder.retrofit; } private static Retrofit retrofit2; public static Retrofit getStringRetrofitInstance(String url) { retrofit2 = new Retrofit.Builder() .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) .addConverterFactory(StringConverterFactory.create()) .baseUrl(url) .client(client) .build(); return retrofit2; } public static Retrofit retrofit3; public static Retrofit getRetrofitInstance(String url) { retrofit3 = new Retrofit.Builder() .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) .addConverterFactory(StringConverterFactory.create()) .baseUrl(url) .client(client) .build(); return retrofit3; } }
创建Service的接口
GET请求
//具体的网络url : 举例子:https://api.douban.com/v2/movie/top250?start=2&count=4 public interface ApiService { @GET("top250") Observable<Entity> getMovies(@Query("start") int start,@Query("count") int count); }
// 最好这么写,参数用变量代替 public interface ApiService { @GET("{url}") Observable<Entity> getMovies(@Path("url") String url, @Query("start") int start, @Query("count") int count); }
POST请求
public interface MovieService { //获取豆瓣Top250 榜单 @FormUrlEncoded @POST("top250") Observable<MovieSubject> getTop250(@Field("start") int start, @Field("count") int count); } 关于Post请求需要注意的几个地方: 必须要有@FormUrlEncoded 配合 Filed使用时
下载文件的GET请求
//必须要加上@Streaming,不然会把下载的东西全部读到内存中去 @Streaming @GET Observable<ResponseBody> downloadFile(@Url String url);
写入ReponseBody到文件系统
/** * 将ResponseBody中的内容保存到本地路径 ;该路径必须已经存在 * * @param body * @param localPath */ public static void writeResponseBodyToDisk(ResponseBody body, String localPath) { File file = new File(localPath); InputStream is = null; OutputStream os = null; long totalLength = body.contentLength(); long currentLength = 0; double rate = 0; byte[] bytes = new byte[4096]; try { os = new FileOutputStream(file); is = body.byteStream(); int length = -1; while ((length = is.read(bytes)) != -1) { os.write(bytes, 0, length); currentLength += length; rate = currentLength * 1.0 / totalLength; } os.flush(); } catch (IOException e) { e.printStackTrace(); } finally { try { if (is != null) { is.close(); } if (os != null) { os.close(); } } catch (IOException e) { e.printStackTrace(); } } }
踩过的坑:
1.Post请求中//获取 任务 @POST("index.php/machine/{url}") Observable<String> getTask(@Path("url") String url, @Body RequestBody requestBody);
注解Post的括号中如果有引用方法的url时,那么方法中的url不能包括斜杠 / ,也不能包括问号 ?
因为斜杠 / 会被转义为 %2F ; ? 会被转义为 %3F ;斜杠和问号只有写在@POST的括号中才不会被转义。
2.Post请求上传多个文件和其他字符串参数
文件上传可以用两种方式来做:
1.使用MultipartBody.Part 类型修饰在函数的文件参数前面;文件的参数和字符串参数分开来做;字符串参数可以用@PartMap来包裹
RequestBody apkBody = RequestBody.create(MediaType.parse("multipart/form-data"),file_apk); MultipartBody.Part partApk = MultipartBody.Part.createFormData("apk_url",file_apk.getName(),apkBody);
2.(用的少)使用@PartMap注解修饰参数类型前面 , 上传多个文件,但是对创建文件的RequestBody做一步处理;这种方式其实是把多个文件和字符串都放在@PartMap修饰的HasMap<String,RequestBody>中即:
RequestBody requestBody = RequestBody.create(MediaType.parse("multipart/form-data"), file); RequestBody requestBody1 = RequestBody.create(MediaType.parse("multipart/form-data"), file1); Map<String, RequestBody> params = new HashMap<>(); params.put(key+"\"; filename=\""+ file.getName(), requestBody); params.put(key1+"\"; filename=\""+ file1.getName(), requestBody1);
3.如果服务器返回值不是一个json,而是一个字符串String。那么我们用的GsonConvertory的Retrofit就不可用了。需要自定义一个StringConvertory.
这种上传方式没有尝试过:
MultipartBody.Part photo1part = MultipartBody.Part.createFormData("pic1", "pic2", requestBody1);
@Multipart @POST("upload.php") Observable<ResponseBody> uploadFile( @Part() List<MultipartBody.Part > files );
5.文件和参数同时上传的时候会遇到参数的value如果是String,会有两个双引号在外面。原因是由于使用了
Map<String,String>的方式,可以使用Map<String,RequestBody>的方式来解决这个问题。
相关文章推荐
- RxJava和Retrofit2.0的结合使用
- RXJava结合retrofit的简单使用
- Retrofit2.0(二)结合Rxjava2使用
- RxJava2和Retrofit2.0的简单使用
- Android框架学习之Retrofit(二)RxJava和Retrofit2.0的结合使用
- Android 优雅的让RxJava2.0+Retrofit2.0结合使用
- Retrofit2.0的学习以及Rxjava与Retrofit2的结合使用
- RxJava2.0 和 Retrofit 结合使用时的配置问题
- 天气预报项目学习总结(- ButterKnife - Retrofit 2.0(okhttp) - Rxjava - Jackson - Ormlite - Mosby简单使用总结)
- Retrofit2.0+RxJava+MVP+Bmob的使用
- Android 中 Retrofit 结合 RxJava使用
- Android基于Retrofit2.0 封装的超好用的RetrofitClient工具类(完美结合RxJava)
- retrofit2+rxjava的结合使用
- Retrofit和RxJava结合使用例子分析
- OkGo,一个专注于让网络请求更简单的框架,与RxJava完美结合,比Retrofit更简单易用。
- Retrofit2.0详解(一简单使用)
- 简单入门使用Retrofit+ rxjava 下载图片
- retrofit2.0的简单使用
- Retrofit结合RxJava个人使用经验
- Rxjava+Retrofit结合使用时的开发技巧