两行代码搞定发送 Retrofit GET/POST 请求
2017-05-06 15:43
459 查看
目前Android开发几乎都离不开网络请求,而很多Android App网络框架都使用Retrofit来发送网络请求和响应交互,其优点是一底层依赖了强大灵活的Okhttp,二是其符合标准的RESTFUL和后端交互更爽。
本身Retrofit已经封装得很好了,其使用也很简单:
所以,即便Retrofit已经做好了大量封装工作,但是如果在app层使用的时候,如果直接使用将会在代码中到处充斥了这样的冗余代码,作为一名资深码农,肯定不会让这样的事情发生,为了偷懒,先要动脑筋。因此,如何更加方便的使用网络请求,让代码看起来更加优雅,这里奉上自己的劳动成果,不敢独享,两行代码搞定请求。
先来看看我最后的使用效果,用起来是像下面这样的:
说明:
1. 上面 GET 和 POST 请求的第一行都是在组装发送请求所需要的参数,第二行即发送请求,请求回来的callback在UI线程,可以直接操作view,默认只需要override 200 response时的操作,如果想对Non-200的response override当然也可以。
2. 上例中的newAppVerInfo和loginInfo都是定义在EHService中的接口函数名(见下)。
3. callback中的NewAppVerInfo和LoginInfo是定义在EHService中的接口函数中Call中的类型,也是你自己最终想得到的。
其中EHService如下:
有没有觉得很方便,很爽?!好的,接下来,我们来看看是如何实现的!这里最核心的代码都封装在RetrofitClient中,首先对于Retrofit的获取采用了单例:
首先通过单例函数initRetrofitClient(),保证了后面无论执行多少次都只产生一次 retrofit 和 service, 这正是requestHttp()在后期所做的。
下面我们再看get函数,其参数分别为getFuncName, String[] paramArray, BaseCallback baseCallback。通过 invokeMethod(requestHttp(), getFuncName, paramArray);反射的方式间接执行了原本定义在EHService中的接口函数,从而实现了发送请求。主要借助了invokeMethod执行了变参函数。
首先通过反射在EHService Class中找到参数中传过来的对应的Method,然后赋给其paramArray参数作为接口中对应的参数执行即可。
get请求相对比较容易理解,下面主要看看post相对来说比较复杂一点的是,其发送请求时需要在post请求有一个json的body带参数过去,而且这些参数的格式都是不确定的。这里我使用了泛型,开发者自行定义json对应的bean entity即可在内部自动解析为json格式进行发送。同理这里也是使用了反射,通过postFuncName找到EHService Class中找到参数中传过来的对应的Method,然后执行即可。
这里有一个BaseCallback callback,那么BaseCallback里又做了什么呢?我们来看:
这里实际上是对http response在应用层(即返回的json)中做了进一步的封装处理,把onResponse json中的 return code 分成了 200 OK 和 non-200 response两种情况,只把200 response作为abstract留给开发者来override,当然如果想对non-200做处理也可以在callback中override。
好的,基本上基本原理就是如此简单。如果有什么问题,可以留言。另外,你可以去github中看看具体的代码和实例
https://github.com/AndrewXiao/SimpleRetrofit
本身Retrofit已经封装得很好了,其使用也很简单:
//定以接口 public interface GitHubService { @GET("users/{user}/repos") Call<List<Repo>> listRepos(@Path("user") String user); } //获取实例 Retrofit retrofit = new Retrofit.Builder() //设置OKHttpClient,如果不设置会提供一个默认的 .client(new OkHttpClient()) //设置baseUrl .baseUrl("https://api.github.com/") //添加Gson转换器 .addConverterFactory(GsonConverterFactory.create()) .build(); GitHubService service = retrofit.create(GitHubService.class); Call<List<Repo>> call = service.listRepos("octocat"); //异步请求 clone.enqueue(new Callback<List<Repo>>() { @Override public void onResponse(Call<List<Repo>> call, Response<List<Repo>> response) { // Get result bean from response.body() List<Repo> repos = response.body(); ... } @Override public void onFailure(Call<List<Repo>> call, Throwable t) { } });
所以,即便Retrofit已经做好了大量封装工作,但是如果在app层使用的时候,如果直接使用将会在代码中到处充斥了这样的冗余代码,作为一名资深码农,肯定不会让这样的事情发生,为了偷懒,先要动脑筋。因此,如何更加方便的使用网络请求,让代码看起来更加优雅,这里奉上自己的劳动成果,不敢独享,两行代码搞定请求。
先来看看我最后的使用效果,用起来是像下面这样的:
/** * GET 请求 示例: */ private void clickGetButton(){ String [] strArray = {"Android", "1"}; RetrofitClient.get("newAppVerInfo", strArray, new BaseCallback<NewAppVerInfo>() { @Override protected void on200Resp(NewAppVerInfo newAppVerInfo){ textView.setText("收到GET结果: newAppVerInfo = " + new Gson().toJson(newAppVerInfo)); } }); } /** * POST 请求 示例: */ private void clickPostButton(){ LoginReq loginReq = new LoginReq("13051892977", FormatUtil.md5("123456"), "phoneID"); RetrofitClient.post("loginInfo", loginReq, new BaseCallback<LoginInfo>() { @Override protected void on200Resp(LoginInfo loginInfo){ textView.setText("收到POST结果: loginInfo = " + new Gson().toJson(loginInfo)); } }); }
说明:
1. 上面 GET 和 POST 请求的第一行都是在组装发送请求所需要的参数,第二行即发送请求,请求回来的callback在UI线程,可以直接操作view,默认只需要override 200 response时的操作,如果想对Non-200的response override当然也可以。
2. 上例中的newAppVerInfo和loginInfo都是定义在EHService中的接口函数名(见下)。
3. callback中的NewAppVerInfo和LoginInfo是定义在EHService中的接口函数中Call中的类型,也是你自己最终想得到的。
其中EHService如下:
public interface EHService { @GET("product/getNewVersionInfo.json") Call<NewAppVerInfo> newAppVerInfo(@Query("OSType") String OSType, @Query("DevType") String DevType); @Headers({"Content-Type: application/json","Accept: application/json"})//需要添加头 @POST("login/login.json") Call<LoginInfo> loginInfo(@Body RequestBody loginReq); }
有没有觉得很方便,很爽?!好的,接下来,我们来看看是如何实现的!这里最核心的代码都封装在RetrofitClient中,首先对于Retrofit的获取采用了单例:
public class RetrofitClient { private static Retrofit retrofit; private static EHService service; private RetrofitClient(){} private static void initRetrofitClient(){ if(retrofit == null || service == null){ synchronized (RetrofitClient.class){ if(retrofit == null){ retrofit = new Retrofit.Builder() .baseUrl("https://your.base.url/") .addConverterFactory(GsonConverterFactory.create()) .build(); service = retrofit.create(EHService.class); } } } } public static EHService requestHttp(){ initRetrofitClient(); return service; } public static <E extends BaseModel> Call<E> get(String getFuncName, String[] paramArray, BaseCallback<E> baseCallback){ Call<E> typeCall = null; try { typeCall = (Call<E>) invokeMethod(requestHttp(), getFuncName, paramArray); typeCall.enqueue(baseCallback); }catch (NoSuchMethodException e){ Log.e("TAG", "NoSuchMethodException e = " + e.getMessage()); }catch (IllegalAccessException e){ Log.e("TAG", "IllegalAccessException e = " + e.getMessage()); }catch (InvocationTargetException e){ Log.e("TAG", "InvocationTargetException e = " + e.getMessage()); }catch (Exception e){ Log.e("TAG", "Exception e = " + e.getMessage()); } return typeCall; } /** * 反射调用方法 * @param newObj 实例化的一个对象 * @param methodName 对象的方法名 * @param args 参数数组 * @return 返回值 * @throws Exception */ public static Object invokeMethod(Object newObj, String methodName, Object[] args)throws Exception { Class ownerClass = newObj.getClass(); Class[] argsClass = new Class[args.length]; for (int i = 0, j = args.length; i < j; i++) { argsClass[i] = args[i].getClass(); } Method method = ownerClass.getMethod(methodName, argsClass); return method.invoke(newObj, args); } public static <T, E extends BaseModel> Call<E> post(String postFuncName, T postBean, BaseCallback<E> baseCallback){ Call<E> typeCall = null; RequestBody requestBody = getRequestBody(postBean); try { Method EHServiceMethod = EHService.class.getDeclaredMethod(postFuncName, RequestBody.class); typeCall = (Call<E>) EHServiceMethod.invoke(requestHttp(), requestBody); typeCall.enqueue(baseCallback); }catch (NoSuchMethodException e){ Log.e("TAG", "NoSuchMethodException e = " + e.getMessage()); }catch (IllegalAccessException e){ Log.e("TAG", "IllegalAccessException e = " + e.getMessage()); }catch (InvocationTargetException e){ Log.e("TAG", "InvocationTargetException e = " + e.getMessage()); }catch (Exception e){ Log.e("TAG", "Exception e = " + e.getMessage()); } return typeCall; } public static <T> RequestBody getRequestBody(T postBean){ //通过Gson将Bean转化为Json字符串形式 String reqBeanJson = new Gson().toJson(postBean); return RequestBody.create(okhttp3.MediaType.parse("application/json; charset=utf-8"), reqBeanJson); } }
首先通过单例函数initRetrofitClient(),保证了后面无论执行多少次都只产生一次 retrofit 和 service, 这正是requestHttp()在后期所做的。
下面我们再看get函数,其参数分别为getFuncName, String[] paramArray, BaseCallback baseCallback。通过 invokeMethod(requestHttp(), getFuncName, paramArray);反射的方式间接执行了原本定义在EHService中的接口函数,从而实现了发送请求。主要借助了invokeMethod执行了变参函数。
首先通过反射在EHService Class中找到参数中传过来的对应的Method,然后赋给其paramArray参数作为接口中对应的参数执行即可。
get请求相对比较容易理解,下面主要看看post相对来说比较复杂一点的是,其发送请求时需要在post请求有一个json的body带参数过去,而且这些参数的格式都是不确定的。这里我使用了泛型,开发者自行定义json对应的bean entity即可在内部自动解析为json格式进行发送。同理这里也是使用了反射,通过postFuncName找到EHService Class中找到参数中传过来的对应的Method,然后执行即可。
这里有一个BaseCallback callback,那么BaseCallback里又做了什么呢?我们来看:
public abstract class BaseCallback<T extends BaseModel> implements Callback<T> { @Override public void onResponse(Call<T> call, Response<T> response) { int networkRespCode = response.raw().code(); Log.i("TAG", "BaseCallback onResponse! networkRespCode = " + networkRespCode); T bean = response.body(); if (networkRespCode == 200) { // 200是服务器有合理响应, IP层的HTTP回应 if(bean.getCode() == 200) on200Resp(bean); // Response 里 json 层 code: 200 else onNon200Resp(bean); }else onFailure(call, new RuntimeException("response error,detail = " + response.raw().toString())); } @Override public void onFailure(Call<T> call, Throwable t) { Log.e("TAG", "BaseCallback onFailure! call = " + call.request().url().toString()); onFailure(t); } /** * on200Resp() onNon200Resp() onFailure() 无论如何都将是在UI线程中执行!即使是把 retrofitClient 放入子线程中仍是如此! * 当需要处理 onNon200Resp,onFailure 的场景时,则 override 此方法 * */ protected abstract void on200Resp(T bean); void onNon200Resp(T bean){ Log.e("TAG", "receive non-200 response, code is " + bean.getCode()); } void onFailure(Throwable t){ Log.e("TAG", "on Failure! Throwable message = " + t.getMessage() + ", stack trace = " + t.getStackTrace()); } }
这里实际上是对http response在应用层(即返回的json)中做了进一步的封装处理,把onResponse json中的 return code 分成了 200 OK 和 non-200 response两种情况,只把200 response作为abstract留给开发者来override,当然如果想对non-200做处理也可以在callback中override。
好的,基本上基本原理就是如此简单。如果有什么问题,可以留言。另外,你可以去github中看看具体的代码和实例
https://github.com/AndrewXiao/SimpleRetrofit
相关文章推荐
- Android中使用Json和Xml与服务器进行通信,使用代码发送Get和Post请求,http请求辅助类
- Python 使用requests模块发送GET和POST请求的实现代码
- Python 使用requests模块发送GET和POST请求的实现代码
- C#代码模拟http发送get和post请求
- php发送get、post请求的6种方法代码示例
- Android例子—HttpURLConnection发送POST、GET请求代码示例
- java发送http的get、post请求实现代码
- Java代码中利用httpClient发送post、get请求
- java代码分别发送get和post请求。
- Android下通过httpClient发送GET和POST请求的实例代码
- 通过HttpWebRequest分别向服务器发送GET或POST请求
- 【转】python发送GET或POST请求以便干一些趣事
- 如何使用SOCKET 发送HTTP1.1 GET POST请求包
- 使用Java发送GET、POST请求
- Android 发送请求 HTTP GET/POST
- 使用Java发送GET、POST请求
- [Socket]利用Android下的HttpClient发送GET && POST请求
- xmlrequest通过GET,POST方法向服务器发送请求
- Android向Web站点发送GET请求、POST请求
- 使用Java发送GET、POST请求