Retrofit基础入门
来源:互联网 发布:ups 寿命 知乎 编辑:程序博客网 时间:2024/06/18 10:29
Retrofit是Square公司开发的一款针对Android网络请求的框架,Retrofit2底层基于OkHttp实现的,OkHttp现在已经得到Google官方认可,大量的app都采用OkHttp做网络请求,其源码详见OkHttp Github。
二、如何使用
首先需要在build.gradle文件中引入需要的第三包,配置如下:
compile 'com.squareup.retrofit2:retrofit:2.3.0' compile 'com.squareup.retrofit2:converter-scalars:2.3.0' compile 'com.squareup.retrofit2:adapter-rxjava:2.3.0' compile 'com.squareup.retrofit2:converter-gson:2.3.0' compile 'io.reactivex:rxjava:1.3.0' compile 'io.reactivex:rxandroid:1.2.1'
导入第三方包,接下来是使用retrofit进行网络请求,接下来我会使用我项目内的代码进行说明
Post请求:
Post请求需要把请求参数放置在请求体中,而非拼接在url后面
/** * 普通写法 */ //附近的商品 @POST("open/market/getNearbyGoods.do") Observable<String> getNearbyGoods(@QueryMap Map<String, String> map);注释写的比较清晰,所有我这里说下,它的缺点,每个接口都需要写一个类似的方法,比较繁琐,重新造轮子。下面是优化版:
/** * post方式 map传参 * @param url * @param maps * @return */ @POST("{url}") Observable<String> executePost( @Path(value = "url", encoded = true) String url, @QueryMap Map<String, String> maps);
/** * post方式 json传参 * @param url * @param jsonStr * @return */ @POST("{url}") Observable<String> json( @Path(value = "url", encoded = true) String url, @Body RequestBody jsonStr);
上传文件
/** * post方式 上传单个文件 * @param url * @param description 文件描述 * @param file * @return */ @Multipart @POST("{url}") Observable<String> upLoadFile( @Path(value = "url", encoded = true) String url, @Part("description") RequestBody description, @Part MultipartBody.Part file); /** * post方式 上传多个文件 * @param url * @param maps * @return */ @POST("{url}") Observable<String> upLoadFiles( @Path(value = "url", encoded = true) String url, @PartMap() Map<String, MultipartBody.Part> maps);图文上传
/** * post方式 图文同时上传 * @param url * @param partMap * @param file * @return */ @Multipart @POST Observable<String> uploadFileWithPartMap( @Url() String url, @QueryMap() Map<String, String> partMap, @Part("file") MultipartBody.Part file);Get请求:
get请求跟post请求差不多,这里只写一些
/** * get方式 map传参 * @param url * @param maps * @return */ @GET("{url}") Observable<String> executeGet( @Path(value = "url", encoded = true) String url, @QueryMap Map<String, String> maps );
/** * get方式 下载文件 * @param fileUrl * @return */ @Streaming @GET Observable<ResponseBody> downloadFile(@Url String fileUrl);
1.创建业务请求接口,具体代码如下:
这里需要稍作说明,@GET注解就表示get请求,@Query表示请求参数,将会以key=value的方式拼接在url后面
public interface BlueService { @GET("book/search") Call<BookSearchResponse> getSearchBooks(@Query("q") String name, @Query("tag") String tag, @Query("start") int start, @Query("count") int count);}
2.创建一个Retrofit的示例,并完成相应的配置
Retrofit retrofit = new Retrofit.Builder() .baseUrl("https://api.douban.com/v2/") .addConverterFactory(GsonConverterFactory.create()) .build();BlueService service = retrofit.create(BlueService.class);这里的baseUrl就是网络请求URL相对固定的地址,一般包括请求协议(如Http)、域名或IP地址、端口号等,当然还会有很多其他的配置,下文会详细介绍。还有addConverterFactory方法表示需要用什么转换器来解析返回值,GsonConverterFactory.create()表示调用Gson库来解析json返回值,具体的下文还会做详细介绍。
3.调用请求方法,并得到Call实例
Call<BookSearchResponse> call = mBlueService.getSearchBooks("小王子", "", 0, 3);Call其实在Retrofit中就是行使网络请求并处理返回值的类,调用的时候会把需要拼接的参数传递进去
4.使用Call实例完成同步或异步请求
4.1同步请求
BookSearchResponse response = call.execute().body();这里需要注意的是网络请求一定要在子线程中完成,不能直接在UI线程执行,不然会crash
4.2异步请求
call.enqueue(new Callback<BookSearchResponse>() {@Overridepublic void onResponse(Call<BookSearchResponse> call, Response<BookSearchResponse> response) {asyncText.setText("异步请求结果: " + response.body().books.get(0).altTitle);}@Overridepublic void onFailure(Call<BookSearchResponse> call, Throwable t) {}});上面是简单的使用
我项目中使用的是rxjava+retrofit框架,目前是比较大众的写法,网上有许多框架的封装。这里我把我自己的代码直接上
/** * RetrofitClient */public class RetrofitClient { private static final int DEFAULT_TIMEOUT = 20; private Retrofit retrofit; private Cache cache = null; private File httpCacheDirectory; private static OkHttpClient okHttpClient; public static RetrofitClient getInstance(Context context) { return new RetrofitClient(context); } public RetrofitClient(Context context) { if (httpCacheDirectory == null) { httpCacheDirectory = new File(context.getCacheDir(), "tamic_cache"); } try { if (cache == null) { cache = new Cache(httpCacheDirectory, 10 * 1024 * 1024); } } catch (Exception e) { Log.e("OKHttp", "Could not create http cache", e); } okHttpClient = new OkHttpClient.Builder() //设置可以从传入的HTTP响应接受cookie并向传出HTTP请求提供cookie的处理程序。// .cookieJar(new NovateCookieManger(context)) //设置响应缓存用于读取和写入缓存响应。 .cache(cache) //链接超时 .connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS) .readTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS) //新链接默认超时时间 .writeTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS) //设置用于回收HTTP和HTTPS连接的连接池。 .connectionPool(new ConnectionPool(8, 15, TimeUnit.SECONDS)) // 这里你可以根据自己的机型设置同时连接的个数和时间,我这里8个,和每个保持时间为10s .build(); retrofit = new Retrofit.Builder() .client(okHttpClient) .baseUrl(BaseRetrofit.API) //增加返回值为String的支持 .addConverterFactory(ScalarsConverterFactory.create()) //增加返回值为Gson的支持(以实体类返回) .addConverterFactory(GsonConverterFactory.create()) //增加返回值为Oservable<T>的支持 .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) .build(); } /** * post方式的访问api * * @param url * @param map * @param subscribe * @return */ public Subscription initMap(String url, Map<String, String> map, Subscriber<String> subscribe) { BaseRetrofit service = retrofit.create(BaseRetrofit.class); Subscription subscription = service.executePost(url, map) .compose(schedulersTransformer()) .subscribe(subscribe); return subscription; } /** * post方式 单个文件上传 * * @param url * @param file * @param subscribe * @return */ public Subscription upLoadFile(String url, File file, Subscriber<String> subscribe) { // 创建 RequestBody,用于封装构建RequestBody RequestBody requestFile = RequestBody.create(MediaType.parse("multipart/form-data"), file); // MultipartBody.Part 和后端约定好Key,这里的partName是用image MultipartBody.Part body = MultipartBody.Part.createFormData("image", file.getName(), requestFile); // 添加描述 String descriptionString = "hello, 这是文件描述"; RequestBody description = RequestBody.create(MediaType.parse("multipart/form-data"), descriptionString); BaseRetrofit service = retrofit.create(BaseRetrofit.class); Subscription subscription = service.upLoadFile(url, description, body) .compose(schedulersTransformer()) .subscribe(subscribe); return subscription; } /** * post方式 多个文件上传 * * @param url * @param files * @param subscribe * @return */ @RequiresApi(api = Build.VERSION_CODES.KITKAT) public Subscription upLoadFiles(String url, Map<String, File> files, Subscriber<String> subscribe) { Map<String, MultipartBody.Part> map = new ArrayMap<>(); for (int i = 0; i < files.size(); i++) { // 创建 RequestBody,用于封装构建RequestBody RequestBody requestFile = RequestBody.create(MediaType.parse("multipart/form-data"), files.get(i)); // MultipartBody.Part 和后端约定好Key,这里的partName是用image MultipartBody.Part body = MultipartBody.Part.createFormData("image", files.get(i).getName(), requestFile); map.put(i + "", body); } // 添加描述 BaseRetrofit service = retrofit.create(BaseRetrofit.class); Subscription subscription = service.upLoadFiles(url, map) .compose(schedulersTransformer()) .subscribe(subscribe); return subscription; } /** * get方式 下载文件 * @param url 文件url * @param subscribe * @return */ public Subscription downLoadFile(String url, Subscriber<ResponseBody> subscribe) { // 添加描述 BaseRetrofit service = retrofit.create(BaseRetrofit.class); Subscription subscription = service.downloadFile(url) .subscribeOn(Schedulers.io()) .subscribe(subscribe); return subscription; } Observable.Transformer schedulersTransformer() { return new Observable.Transformer() { @Override public Object call(Object observable) { return ((Observable) observable).subscribeOn(Schedulers.io()) .unsubscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()); } /* @Override public Observable call(Observable observable) { return observable.subscribeOn(Schedulers.io()) .unsubscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()); }*/ }; }}网络请求错误进行自定义判断
public class ExceptionHandle { private static final int UNAUTHORIZED = 401; private static final int FORBIDDEN = 403; private static final int NOT_FOUND = 404; private static final int REQUEST_TIMEOUT = 408; private static final int INTERNAL_SERVER_ERROR = 500; private static final int BAD_GATEWAY = 502; private static final int SERVICE_UNAVAILABLE = 503; private static final int GATEWAY_TIMEOUT = 504; public static ResponeThrowable handleException(Throwable e) { ResponeThrowable ex; if (e instanceof HttpException) { HttpException httpException = (HttpException) e; ex = new ResponeThrowable(e, ERROR.HTTP_ERROR); switch (httpException.code()) { case UNAUTHORIZED: case FORBIDDEN: case NOT_FOUND: case REQUEST_TIMEOUT: case GATEWAY_TIMEOUT: case INTERNAL_SERVER_ERROR: case BAD_GATEWAY: case SERVICE_UNAVAILABLE: default: ex.message = "网络错误"; break; } return ex; } else if (e instanceof ServerException) { ServerException resultException = (ServerException) e; ex = new ResponeThrowable(resultException, resultException.code); ex.message = resultException.message; return ex; } else if (e instanceof JsonParseException || e instanceof JSONException || e instanceof ParseException) { ex = new ResponeThrowable(e, ERROR.PARSE_ERROR); ex.message = "解析错误"; return ex; } else if (e instanceof ConnectException) { ex = new ResponeThrowable(e, ERROR.NETWORD_ERROR); ex.message = "连接失败"; return ex; } else if (e instanceof javax.net.ssl.SSLHandshakeException) { ex = new ResponeThrowable(e, ERROR.SSL_ERROR); ex.message = "证书验证失败"; return ex; } else if (e instanceof ConnectTimeoutException) { ex = new ResponeThrowable(e, ERROR.TIMEOUT_ERROR); ex.message = "连接超时"; return ex; } else if (e instanceof java.net.SocketTimeoutException) { ex = new ResponeThrowable(e, ERROR.TIMEOUT_ERROR); ex.message = "连接超时"; return ex; } else { if (!NetworkUtil.isNetworkAvailable(App.getInstance())) { ex = new ResponeThrowable(e, ERROR.UNKNOWN); ex.message = "无网络,请连接网络"; }else{ ex = new ResponeThrowable(e, ERROR.UNKNOWN); ex.message = "未知错误"; } return ex; } } /** * 约定异常 */ class ERROR { /** * 未知错误 */ public static final int UNKNOWN = 1000; /** * 解析错误 */ public static final int PARSE_ERROR = 1001; /** * 网络错误 */ public static final int NETWORD_ERROR = 1002; /** * 协议出错 */ public static final int HTTP_ERROR = 1003; /** * 证书出错 */ public static final int SSL_ERROR = 1005; /** * 连接超时 */ public static final int TIMEOUT_ERROR = 1006; } public static class ResponeThrowable extends Exception { public int code; public String message; public ResponeThrowable(Throwable throwable, int code) { super(throwable); this.code = code; } } public class ServerException extends RuntimeException { public int code; public String message; }}
public abstract class BaseSubscriber<T> extends Subscriber<T> { @Override public void onStart() { onReStart(); super.onStart(); } @Override public void onError(Throwable e) { if (e instanceof ExceptionHandle.ResponeThrowable) { onError((ExceptionHandle.ResponeThrowable) e); } else { onError(ExceptionHandle.handleException(e)); } } @Override public void onNext(T t) { BaseResponse baseResponse = ResponseParserUtils.parseResponse((String) t, String.class, false); onNext(baseResponse); } public abstract void onNext(BaseResponse baseResponse); public abstract void onReStart(); public abstract void onError(ExceptionHandle.ResponeThrowable e);}准备好了之后,进行网络请求方法:
Subscription subscription = RetrofitClient.getInstance(this) .downLoadFile(downUrl, new Subscriber<ResponseBody>() { @Override public void onCompleted() { stopService(intent); CatalogActivity.downOk=true; } @Override public void onError(Throwable e) { LogUtils.i("DownNovelService", e.toString()); ToastUtils.showMessageLong(e.toString()); stopService(intent); CatalogActivity.downOk=true; } @Override public void onNext(ResponseBody responseBody) { if (WriteFileManager.writeResponseBodyToDisk(responseBody, novelName + ".text")) { ToastUtils.showMessageLong("下载成功"); } else { ToastUtils.showMessageLong("下载失败"); } } });三、其他需要知道事项
网络请求看起来是那么完美,但是仔细看并进行试验时,你就会发现,怎么没有取消网络请求的方法。
retrofit取消请求:call.cancel();
rxjava取消订阅:Subscription.unsubscribe();
看具体情况使用。
这里我封装了一个rxjava+retrofit取消请求的类,直接上代码:
public interface RxActionManager<T> { void add(T tag, Subscription subscription); void remove(T tag); void cancel(T tag); void cancelAll();}
/** * describe Retrofit+RxJava取消接口管理 * authors liuyaolin * createTime 2017/6/6 16:31 */public class RxApiManager implements RxActionManager<Object> { private static RxApiManager sInstance = null; private ArrayMap<Object, Subscription> maps; public static RxApiManager get() { if (sInstance == null) { synchronized (RxApiManager.class) { if (sInstance == null) { sInstance = new RxApiManager(); } } } return sInstance; } private RxApiManager() { maps = new ArrayMap<>(); } @Override public void add(Object tag, Subscription subscription) { maps.put(tag, subscription); } @Override public void remove(Object tag) { if (!maps.isEmpty()) { maps.remove(tag); } } public void removeAll() { if (!maps.isEmpty()) { maps.clear(); } } @Override public void cancel(Object tag) { if (maps.isEmpty()) { return; } if (maps.get(tag) == null) { return; } if (!maps.get(tag).isUnsubscribed()) { maps.get(tag).unsubscribe(); maps.remove(tag); } } @Override public void cancelAll() { if (maps.isEmpty()) { return; } Set<Object> keys = maps.keySet(); for (Object apiKey : keys) { cancel(apiKey); } }}调用方法是:
先添加请求到Map集合内
RxApiManager.get().add(this, subscription);
RxApiManager.get().cancel(this);
四、结束语
关于Retrofit常用的方法基本上已经介绍完了,有些请求由于工作保密性的原因,所以就没有放出来,但是基本的方法和操作都是有的,仿照文中提到的代码就可以实现你想要的功能。参考了网络一些retrofit相关资料。由于本人能力有限,有错误或者表述不准确的地方还望多多留言指正。
- Retrofit基础入门(1)
- Retrofit基础入门
- Retrofit入门
- retrofit入门
- Retrofit入门
- Retrofit入门
- #Retrofit 入门--Part 1
- Retrofit 入门--part2
- Retrofit使用入门
- Retrofit 入门和提高
- Retrofit学习入门
- Retrofit网络请求入门
- Retrofit入门学习
- Retrofit简单入门
- Retrofit 入门篇
- Retrofit简单入门
- Retrofit 的初级入门
- Andriod retrofit 入门
- Gson转list
- hbase安装
- Android Studio 运行时乱码
- FastJson高性能JSON开发包
- CodeForces569C【你会不会暴力啊】
- Retrofit基础入门
- Python 3从入门到精通13-读文件内容
- Zedboard学习(五):MIO与EMIO操作
- css小技巧
- fetch移动端浏览器兼容问题解决
- 单链表的简单实现
- RestEasy 框架了解
- 图:图的基本概念
- Lock wait timeout exceeded; try restarting transaction错误