MyUtil
该工具类获得了一个全局的 Context ,以及根据此context,创建了开启加载动画以及关闭加载动画的方法
public class MyUtil { /** * 全局context */ private static Application mApplicationContext; private static RxDialogLoading rxDialogLoading; /** * @param app 初始化全局context */ public static void initialize(Application app) { mApplicationContext = app; } /** * 获得全局context * * @return 当前的全局context */ public static Application getApplication() { return mApplicationContext; } /** * 关闭键盘 */ public static void closeSoftKeyboard() { InputMethodManager inputManger = (InputMethodManager) ActivityUtil.getCurrentActivity().getSystemService(Context.INPUT_METHOD_SERVICE); if (inputManger != null) { inputManger.hideSoftInputFromWindow(ActivityUtil.getCurrentActivity().getWindow().getDecorView().getWindowToken(), 0); } } public static String getString(int id) { return getApplication().getResources().getString(id); } /** * 展示dialog * * @param context 传入当前Acitivity */ public static void showLoading(Context context){ if (rxDialogLoading == null){ rxDialogLoading = new RxDialogLoading(context); rxDialogLoading.setCanceledOnTouchOutside(false); } rxDialogLoading.show(); } /** * 成功隐藏dialog,显示成功 */ public static void dismissSuccessLoading(){ rxDialogLoading.cancel(RxDialogLoading.RxCancelType.success,getString(R.string.load_success)); } /** * 失败隐藏dialog,显示失败 */ public static void dismissFailedLoading(){ rxDialogLoading.cancel(RxDialogLoading.RxCancelType.error,getString(R.string.load_error)); } } 复制代码
Retrofit + Rxjava 打造优雅网络请求方式
由于该模块代码繁多,文章不会描述每一个类,完整代码请查阅http
其中的 cookie 包是用于做登录状态持久化,但是本demo中未用到
gson 包是做了一个转换器,对网络数据的请求报文和响应报文做了一次数据筛查
API 类是定义了所有的网络请求方法
RetrofitService 类是对该网络模块的集成的方法,是 Retrofit 的核心方法
BaseResponseBodyConverter
该方法是继承了类型为响应报文的 Retrofit 转换器类,可以对对响应报文做数据筛查。我们可以筛查出响应的报文的错误码或者错误描述进行自动的异常处理。
例如返回的错误码描述为当前登录状态过期,那么我们可以取消登录状态,程序自动跳转到登录页面中。
亦或是错误码为非正常状态下,自动抛出自定义的异常,然后App对该异常做 Toast 描述之类的
public class BaseResponseBodyConverter<T> implements Converter<ResponseBody, T> { private final TypeAdapter<T> adapter; BaseResponseBodyConverter(TypeAdapter<T> adapter) { this.adapter = adapter; } @Override public T convert(ResponseBody value) throws IOException { String jsonString = value.string(); try{ JSONObject object = new JSONObject(jsonString); int code = object.getInt(MyUtil.getString(R.string.code)); String data ; if (code == 1) return adapter.fromJson(jsonString); else data = object.getString(MyUtil.getString(R.string.msg)); throw new BaseException(code, data); }catch (JSONException ex){ ex.printStackTrace(); try { JSONObject object = new JSONObject(jsonString); int error_code = object.getJSONObject("data").getInt(MyUtil.getString(R.string.error_code)); if (0 != error_code ) { String data; data = object.getJSONObject("data").getString(MyUtil.getString(R.string.error_msg)); //异常处理 throw new BaseException(error_code, data); } //正确返回整个json return adapter.fromJson(jsonString); } catch (JSONException e) { e.printStackTrace(); //数据解析异常即json格式有变动 throw new BaseException(MyUtil.getString(R.string.PARSE_ERROR_MSG)); } }finally { value.close(); } } } 复制代码
需要注意的是,我们需要针对不同格式的响应报文,定制不同的筛查策略和处理逻辑
MoreBaseUrlInterceptor
自定义一个过滤器,在该过滤器中,我们可以对请求的做一些自动的更改
例如下例,我们可以在检测到请求头中带 urlName
字段的时候,去做一个对应的 BaseUrl
的更新;我们也还可以在这里做一些譬如key这些字段的添加等等
public class MoreBaseUrlInterceptor implements Interceptor { private final HashMap<String,String> keyUrl; public MoreBaseUrlInterceptor(HashMap<String, String> keyUrl) { this.keyUrl = keyUrl; } @Override public Response intercept(Chain chain) throws IOException { //获取原始的originalRequest Request originalRequest = chain.request(); //获取老的url HttpUrl oldUrl = originalRequest.url(); //获取originalRequest的创建者builder Request.Builder builder = originalRequest.newBuilder(); //获取头信息的集合如:base,geo List<String> urlNameList = originalRequest.headers("urlName"); if (urlNameList.size() > 0) { //删除原有配置中的值,就是namesAndValues集合里的值 builder.removeHeader("urlName"); //获取头信息中配置的value,如:m或者mock String urlName = urlNameList.get(0); HttpUrl baseURL; //根据头信息中配置的value,来匹配新的base_url地址 baseURL = HttpUrl.parse(Objects.requireNonNull(keyUrl.get(urlName))); //重建新的HttpUrl,需要重新设置的url部分 HttpUrl newHttpUrl = oldUrl.newBuilder() .scheme(baseURL.scheme())//http协议如:http或者https .host(baseURL.host())//主机地址 .encodedPath(baseURL.encodedPath() + oldUrl.encodedPath().substring(1))//构建路径,为适配MOCK中给出的BaseURL带有Path路径的情况 .port(baseURL.port())//端口 .build(); //获取处理后的新newRequest Request newRequest = builder.url(newHttpUrl).build(); return chain.proceed(newRequest); }else{ Request reOriginalRequest = builder.url(oldUrl).build(); return chain.proceed(reOriginalRequest); } } } 复制代码
RetrofitService
该类是 Retrofit 服务类,对外提供一个服务的单例,然后添加好前面编写的转换器以及过滤器等信息。这样子供外部统一调用这个 Retrofit 单例即可。
public class RetrofitService { private volatile static RetrofitService apiRetrofit; private API.SZApi apiServer; /** * 单例调用 * * @return RetrofitService */ public static RetrofitService getInstance() { if (apiRetrofit == null) { synchronized (Object.class) { if (apiRetrofit == null) { apiRetrofit = new RetrofitService(); } } } return apiRetrofit; } /** * 获取api对象 * * @return api对象 */ public API.SZApi getApiService() { return apiServer; } /** * 初始化retrofit */ private RetrofitService() { //配置okHttp并设置时间、日志信息和cookies HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor(); httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY); OkHttpClient okHttpClient = new OkHttpClient.Builder() .addInterceptor(new MoreBaseUrlInterceptor(API.getKeyUrl())) .addInterceptor(httpLoggingInterceptor) //设置超时时间 .connectTimeout(15, TimeUnit.SECONDS) //设置Cookie持久化 // .cookieJar(new CookiesManager(MyUtil.getApplication())) .build(); //关联okHttp并加上rxJava和Gson的配置和baseUrl Retrofit retrofit = new Retrofit.Builder() .client(okHttpClient) .addConverterFactory(ScalarsConverterFactory.create()) .addConverterFactory(BaseConverterFactory.create()) .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) .baseUrl(API.BASE_URL) .build(); apiServer = retrofit.create(API.SZApi.class); } } 复制代码