Android 使用Retrofit2问题汇总
来源:互联网 发布:免费的gis软件 编辑:程序博客网 时间:2024/05/17 08:08
Retrofit2引用依赖问题
compile 'io.reactivex:rxjava:1.1.3' compile 'io.reactivex:rxandroid:1.1.0' compile 'com.squareup.retrofit2:retrofit:2.0.2' compile 'com.squareup.retrofit2:converter-gson:2.0.2' compile 'com.squareup.retrofit2:converter-scalars:2.0.2' compile 'com.squareup.retrofit2:adapter-rxjava:2.0.2' compile 'com.jakewharton:butterknife:7.0.1' compile 'com.squareup.okhttp3:okhttp:3.2.0' compile 'com.squareup.okio:okio:1.8.0'
在这里遇到一些坑,如果下面三个少一个,返回他不支持的结果时,就会崩溃,这也是上面为什么会导那么多包的原因。
private static Retrofit getRetrofit(String url) { return new Retrofit.Builder().baseUrl(url) //增加返回值为String的支持 .addConverterFactory(ScalarsConverterFactory.create()) //增加返回值为Gson的支持(以实体类返回) .addConverterFactory(GsonConverterFactory.create()) //增加返回值为Oservable<T>的支持 .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) .build(); }
GET请求
http://wthrcdn.etouch.cn/weather_mini?city=深圳
public interface IWeather { @GET("/weather_mini") Observable<Weather> getWeather(@Query("city") String city);}
public static final String url_weather = "http://wthrcdn.etouch.cn"; public static IWeather getIWeather() { return getRetrofit(url_weather).create(IWeather.class); }
HttpUtil.getIWeather().getWeather("深圳") .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Action1<Weather>() { @Override public void call(Weather weather) { tv.setText(weather.getData().getGanmao()); } });
Post请求
根据后台,Multipart或FormUrlEncoded,如果不知道最好两种都试一下,我在这里也是遇了大坑,如果方式错了,根本就post不上去。。
Multipart
http://122.114.38.95:8857 (这个是用的自己的服务器,后面的人看到这篇博客可能这个api就用不了了)
参数是 action , 如果action=banner就可以返回正确结果否则错误结果
@Multipart @POST("/") Observable<String> getBanner(@Part("action") String action);
public static final String url_bannertest = "http://122.114.38.95:8857";public static IBannerTest getBanner() { return getRetrofit(url_bannertest).create(IBannerTest.class); }
HttpUtil.getBanner().getBanner("banner") .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Action1<String>() { @Override public void call(String s) { tv.setText(s); } });
post上传图片
在这里是用了image++的接口。
http://apicn.imageplusplus.com/analyze?
参数:api_key,api_secret, img
@Multipart @POST("/analyze") Observable<String> upLoadImage( @Part("api_key") String api_key, @Part ("api_secret") String api_secret,@Part MultipartBody.Part file );
public static final String imagepp_url = "http://apicn.imageplusplus.com"; public static IImagePP getIImagePP() { return getRetrofit(imagepp_url).create(IImagePP.class); } public static MultipartBody.Part postFileParams(String key, File file) { RequestBody fileBody = RequestBody.create(MediaType.parse("image/*"), file); return MultipartBody.Part.createFormData(key, file.getName(), fileBody); }
File file = new File(Environment.getExternalStorageDirectory()+"/123.png"); HttpUtil.getIImagePP().upLoadImage("c1a2b3ab56a2f218aed9b2ab3c16ce88","be8318b73cef1c2bcafb6c8a77922436",HttpUtil.postFileParams("img", file)) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Action1<String>() { @Override public void call(String s) { tv.setText(s); } });
这里用到了okhttp的特性,这也是为什么要导入okhttp的原因。
private static Retrofit getRetrofit(String url) { return new Retrofit.Builder().baseUrl(url) .addConverterFactory(ScalarsConverterFactory.create()) .addConverterFactory(GsonConverterFactory.create()) .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) .build(); }
上面说到了Retrofit加入了3句。
ScalarsConverterFactory是支持返回String类型
GsonConverterFactory是支持返回实体类。
RxJavaCallAdapterFactory是支持返回rxJava的Observable。
上面的例子Get请求用到了GsonConverterFactory和RxJavaCallAdapterFactory。
Post用到了ScalarsConverterFactory和RxJavaCallAdapterFactory
少一个都会蹦,所以大家用retrofit需要注意这一点。
线程(Scheduler)
Scheduler是RxJava的线程调度器,可以指定代码执行的线程。RxJava内置了几种线程:
AndroidSchedulers.mainThread() 主线程
Schedulers.immediate() 当前线程,即默认Scheduler
Schedulers.newThread() 启用新线程
Schedulers.io() IO线程,内部是一个数量无上限的线程池,可以进行文件、数据库和网络操作。
Schedulers.computation() CPU计算用的线程,内部是一个数目固定为CPU核数的线程池,适合于CPU密集型计算,不能操作文件、数据库和网络。
在实际项目中,Schedulers选择 newThread 还是io呢?
一般的网络请求应该使用io,因为io使用了无限的线程池,而newThread没有线程池维护
参考:http://blog.csdn.net/jdsjlzx/article/details/51497237
onNext方法出现异常
Observer的onNext方法被调用后,它的onError方法也紧跟着被调用了……我的第一反应是RxJava的Bug?……
当然不是了
@Override public void onNext(T args) { try { if (!done) { actual.onNext(args); } } catch (Throwable e) { // we handle here instead of another method so we don't add stacks to the frame // which can prevent it from being able to handle StackOverflow Exceptions.throwIfFatal(e); // handle errors if the onNext implementation fails, not just if the Observable fails onError(e); } }
// handle errors if the onNext implementation fails, not just if the Observable fails
当onNext里我们的函数发生异常时,onError会被调用
API注解
所有请求都需要一个请求方法注解并以相对URL路径作为参数。内建了5个注解:GET, POST, PUT, DELETE, and HEAD
@Path与@Query
@GET("{username}") Call<User> getUser(@Path("username") String username);
@POST("users") Call<List<User>> getUsersBySort(@Query("sort") String sort);
path是可以动态替换的,通过代码一比较就知道区别了。
@map注解
复杂的查询采用@map:
interface QueryGET{ @GET("/sheet") String getString(@Query("name")String name,@Query("age") int age,@QueryMap(encodeNames=true) Map<String, String> filters); }
@GET("/group/{id}/users")List<User> groupList(@Path("id") int groupId, @QueryMap Map<String, String> options);
REQUEST BODY请求体
@POST("/users/new")void createUser(@Body User user, Callback<User> cb);
注意采用一个POJO作为请求体,它会被RestAdapter进行转换。同时POST方式可以传入回调。
FORM ENCODED AND MULTIPART表单域与文件上传
- @FormUrlEncoded修饰表单域,每个表单域子件key-value采用@Field修饰
@FormUrlEncoded@POST("/user/edit")User updateUser(@Field("first_name") String first, @Field("last_name") String last);
- @Multipart修饰用于文件上传,每个Part元素用@Part修饰:
@Multipart@PUT("/user/photo")User updateUser(@Part("photo") TypedFile photo, @Part("description") TypedString description);
Header注解
@Headers("Cache-Control: max-age=640000")@GET("/widget/list")List<Widget> widgetList();
@Headers({ "Accept: application/vnd.github.v3.full+json", "User-Agent: Retrofit-Sample-App"})@GET("/users/{username}")User getUser(@Path("username") String username);
@GET("/user")void getUser(@Header("Authorization") String authorization, Callback<User> callback)
OkHttp 3.0 配置
必须依赖:
compile 'com.squareup.okhttp3:okhttp:3.0.1'compile 'com.squareup.okhttp3:logging-interceptor:3.0.1'
完整配置:
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);OkHttpClient client = new OkHttpClient.Builder() .addInterceptor(interceptor) .retryOnConnectionFailure(true) .connectTimeout(15, TimeUnit.SECONDS) .addNetworkInterceptor(mTokenInterceptor) .build();
- HttpLoggingInterceptor 是一个拦截器,用于输出网络请求和结果的 Log,可以配置 level 为 BASIC / HEADERS / BODY,都很好理解,对应的是原来 retrofit 的 set log level 方法,现在 retrofit 已经没有这个方法了,所以只能到 OkHttp 这边来配置,并且 BODY 对应原来到 FULL.
- retryOnConnectionFailure 方法为设置出现错误进行重新连接。
- connectTimeout 设置超时时间
- addNetworkInterceptor 让所有网络请求都附上你的拦截器,我这里设置了一个 token 拦截器,就是在所有网络请求的 header 加上 token 参数,下面会稍微讲一下这个内容。
让所有网络请求都附上你的 token:
Interceptor mTokenInterceptor = new Interceptor() { @Override public Response intercept(Chain chain) throws IOException { Request originalRequest = chain.request(); if (Your.sToken == null || alreadyHasAuthorizationHeader(originalRequest)) { return chain.proceed(originalRequest); } Request authorised = originalRequest.newBuilder() .header("Authorization", Your.sToken) .build(); return chain.proceed(authorised); }};
解释:
- 那个 if 判断意思是,如果你的 token 是空的,就是还没有请求到 token,比如对于登陆请求,是没有 token 的,只有等到登陆之后才有 token,这时候就不进行附着上 token。另外,如果你的请求中已经带有验证 header 了,比如你手动设置了一个另外的 token,那么也不需要再附着这一个 token.
- header 的 key 通常是 Authorization,如果你的不是这个,可以修改。
如果你需要在遇到诸如 401 Not Authorised 的时候进行刷新 token,可以使用 Authenticator,这是一个专门设计用于当验证出现错误的时候,进行询问获取处理的拦截器:
Authenticator mAuthenticator = new Authenticator() { @Override public Request authenticate(Route route, Response response) throws IOException { Your.sToken = service.refreshToken(); return response.request().newBuilder() .addHeader("Authorization", Your.sToken) .build(); }}
然后,对于以上的两个拦截器,分别使用 OkHttpClient.Builder 对象的 addNetworkInterceptor(mTokenInterceptor) 和 authenticator(mAuthenticator) 即可。
Retrofit配置
Retrofit retrofit = new Retrofit.Builder() .baseUrl(AppConfig.BASE_URL) .client(client) .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) .addConverterFactory(GsonConverterFactory.create(gson)) .build();service = retrofit.create(YourApi.class);
Cookies拦截器
public class CookiesInterceptor implements Interceptor{ private Context context; public CookiesInterceptor(Context context) { this.context = context; } //重写拦截方法,处理自定义的Cookies信息 @Override public Response intercept(Chain chain) throws IOException { Request request = chain.request(); Request compressedRequest = request.newBuilder() .header("cookie", CookieUtil.getCookies(context)) .build(); Response response = chain.proceed(compressedRequest); CookieUtil.saveCookies(response.headers(), context); return response; }}
配置:
public abstract class BaseApi { public static final String API_SERVER = "服务器地址" private static final OkHttpClient mOkHttpClient = new OkHttpClient(); private static Retrofit mRetrofit; protected static Retrofit getRetrofit() { if (Retrofit == null) { Context context = Application.getInstance().getApplicationContext(); //设定30秒超时 mOkHttpClient.setConnectTimeout(30, TimeUnit.SECONDS); //设置拦截器,以用于自定义Cookies的设置 mOkHttpClient.networkInterceptors() .add(new CookiesInterceptor(context)); //设置缓存目录 File cacheDirectory = new File(context.getCacheDir() .getAbsolutePath(), "HttpCache"); Cache cache = new Cache(cacheDirectory, 20 * 1024 * 1024); mOkHttpClient.setCache(cache); //构建Retrofit mRetrofit = new Retrofit.Builder() //配置服务器路径 .baseUrl(API_SERVER + "/") //设置日期解析格式,这样可以直接解析Date类型 .setDateFormat("yyyy-MM-dd HH:mm:ss") //配置转化库,默认是Gson .addConverterFactory(ResponseConverterFactory.create()) //配置回调库,采用RxJava .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) //设置OKHttpClient为网络客户端 .client(mOkHttpClient) .build(); } return mRetrofit; }}
- Android 使用Retrofit2问题汇总
- Android Retrofit2 简单使用
- Android Retrofit2的使用
- Android Retrofit2使用
- 关于android使用retrofit2 demo遇到的问题
- android 关于使用retrofit2.0的一些问题
- Android Retrofit2使用教程-小白篇
- android retrofit2使用全解
- Android键盘使用问题汇总
- Android studio 使用问题汇总
- android studio使用问题汇总
- android Spinner使用问题汇总
- Retrofit2初尝问题汇总及解决方案(含Dagger2)
- retrofit2 RxJava在android中的使用
- Retrofit2.0在android项目中的使用
- Android学习笔记之Retrofit2的使用
- android retrofit2.0框架的使用介绍
- Retrofit2使用
- [Python]第十讲:迭代
- 直播方向的资源收集
- soot代码分析框架的基础知识(一)
- Hadoop MapReduce 程序执行过程
- Android学习系列(18)--App数据格式之解析Json
- Android 使用Retrofit2问题汇总
- POJ 3278 Catch That Cow(DFS)
- nginx rewrite proxy_pass location 的理解
- 针对苹果最新审核要求 为应用兼容IPv6
- 欢迎使用CSDN-markdown编辑器
- Android 面试题总结之Android 基础(二)
- 设置行间距,计算label的高度 ios
- C++primer_第七章_类_学习跟踪
- 如何从频谱图看一副图像的高频和低频成分