Retrofit使用入门
来源:互联网 发布:电脑游戏录制视频软件 编辑:程序博客网 时间:2024/06/08 00:18
Retrofit是Square开发的一个用于网络请求的开源库,内部封装了okhttp,并且和RxAndroid完美的兼容,使得Android的开发效率增加不少的同时也使代码变得清晰易读。
本次的学习建立在上次okhttp学习的基础之上,service端的程序也是通过自己搭建并完成的。服务端的程序比较简单,本次的retrofit学习不对服务端的程序进行过多的讲解。如果有疑问,可以参考上次okhttp的相关内容。首先还是先列举出本次学习用到的资源。
- 官方教程
- github地址
- 李江东博客
- 鸿洋大神
- 推酷上的一篇文章
- 怪盗kidou
- 比较好的资料
搭建使用环境
下载最新的jar或者构建Maven仓库:
<dependency> <groupId>com.squareup.retrofit2</groupId> <artifactId>retrofit</artifactId> <version>2.2.0</version></dependency>
或者直接在项目的build.gradle
中添加如下的依赖
compile 'com.squareup.retrofit2:retrofit:2.2.0'
ps,在添加依赖之前,最好先去github上看当前的最新版本。
在使用之前需要先添加网络访问权限。
<uses-permission android:name="android.permission.INTERNET"/>
使用示例
下面通过使用retrofit实现get、post、文件上传、下载来演示retrofit的使用。
get请求
retrofit在使用的过程中,需要定一个接口对象,我们将它命名为IUserService:
public interface IUserService { @GET("rlogin") Call<ResponseBody> loginByGet(@Query("user") String user, @Query("passwd") String passwd);}
然后在需要MainActivity中构建Retrofit,并生成一个实现接口的方法。
retrofit = new Retrofit.Builder() .baseUrl("http://172.18.9.31:8080/OkhttpTestService/") .build();//构建一个retrofit 对象 IUserService repo = retrofit.create(IUserService.class); Call<ResponseBody> call = repo.loginByGet("reoger","123456");//实例loginByGet对象 call.enqueue(new Callback<ResponseBody>() {//异步执行 @Override public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) { try { mImageView.setText(response.body().string()); } catch (IOException e) { e.printStackTrace(); } } @Override public void onFailure(Call<ResponseBody> call, Throwable t) { mImageView.setText("file to get"); } });
简要的说明一下上后面的代码。首先,在IUserSevice接口中,通过@GET(“rlogin”)注释指定了路径,然后通过后面的loginByGet具体化了url。结合BaseUrl,实例化出来的Url实际上是:http://172.18.9.31:8080/OkhttpTestService/rlogin?user=reoger&passwd=123456,后面的user和passwd是在实例化时传入的。
可能这么讲会有点难懂,先看一个简单的例子。
注解中的参数为请求的相对URL路径@GET("users/list")
就相当与在BaseUrl后加上/users/list。在本例中就相当于:
http://172.18.9.31:8080/OkhttpTestService/users/list
当然,我们可以会遇到URL并不是固定的那种情况。这个时候我们就可以这么写:
@GET("group/{id}/users") //注意 字符串idList<ResponseBody> groupList(@Path("id") int groupId); //注意 Path注解的参数要和前面的字符串一样 id
这个时候我们构造groupList时会传入id,而这个id的值会代替传入的groupId值代替。
{}用于表示是可以替换的区域,而函数参数必须用@Path注解声明。参见上例。
然后,当需要用我们的请求含有参数的时候,这个时候就需要使用@Query
注解来完成。
例如访问:http://baseurl/users?user=username
就需要:
@GET("users") Call<ResponseBody> getUsersBySort(@Query("user") String sort);
点击之后,发现服务端能正确接收来自客服端的请求,并且客服端也能正确接收来自服务端的反馈信息。
这里有一点还需要提出来一下,Call 中的T可以是返回的数据对象,如果返回的是Json数据,我们可以将其解析成一个Java对象的话,可以直接使用该Bean作为返回值,在构建retrofit的时候加上转换方法即可。
为了后面后面的代码比较简洁,我们直接在这里先将后面用到的retrofit和repo对象,已经实现方法executeByEn()统一声明。
retrofit = new Retrofit.Builder() .baseUrl("http://172.18.9.31:8080/OkhttpTestService/") .addConverterFactory(GsonConverterFactory.create()) .build(); repo = retrofit.create(IUserService.class);private void executeByEn(Call<ResponseBody> call) { call.enqueue(new Callback<ResponseBody>() { @Override public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) { try { mImageView.setText(response.body().string()); } catch (IOException e) { e.printStackTrace(); } } @Override public void onFailure(Call<ResponseBody> call, Throwable t) { mImageView.setText("file to get"); } }); }
Post请求
还是先在IUserService中进行申明:
@POST("rlogin") @FormUrlEncoded Call<ResponseBody> loginByPost(@Field("user")String user,@Field("passwd") String passwd);
可以看到,这里我们使用Post作为注解,说明这是一个Post请求。添加FormUrlEncoded
,然后通过@Field
添加参数即可。
访问的代码:
Call<ResponseBody> call = repo.loginByPost("reoger","12346"); executeByEn(call);
此时,我们应该就能同get请求一样将数据传递到服务端,并接收来及服务端的消息。
Post向服务端传递String对象。
首先还是在IUserService中进行声明:
@POST("rpostString") Call<ResponseBody> postString(@Body RequestBody user);
通过 @Body 注解可以声明一个对象作为请求体发送到服务器。
访问代码:
RequestBody body=RequestBody.create(okhttp3.MediaType.parse("application/json; charset=utf-8"),"Here is my server to pass the data, can be a string, but of course, can also be JSON data"); Call<ResponseBody> call = repo.postString(body); executeByEn(call);
这里还是给出服务端的代码吧,服务端接收到数据后会给客户端返回一个收到的信息。
HttpServletRequest request = ServletActionContext.getRequest(); ServletInputStream is = request.getInputStream(); StringBuilder sb = new StringBuilder(); int len = 0; byte[] buf = new byte[1024]; while((len=is.read(buf))!=-1){ sb.append(new String(buf,0,len)); } System.out.println(sb.toString()); HttpServletResponse response = ServletActionContext.getResponse(); PrintWriter writer = response.getWriter(); writer.write("reces: "+sb.toString()); writer.flush(); return null;
访问之后,会发现我们的服务端正确接收到了我们发送的string数据,客户端也成功接收到了来自服务端的数据。
Post 上传Json格式数据
如果你只是单独想上传Json格式的数据到服务器,你完全可以写的更加简单。
@POST("rpostString") Call<ResponseBody> postJson(@Body User user);
访问接口:
Call<ResponseBody> call = repo.postJson(new User("reoger","love")); executeByEn(call);
是吧。两三行代码就解决了。那为什么我们传入User这样一个Bean对象传到服务端的时候就变成了Json数据呢。主要原因我我们在构造retrofit的时候添加的转换方法、
.addConverterFactory(GsonConverterFactory.create())
为此,我们还需要添加额外的依赖:
compile 'com.squareup.retrofit2:converter-gson:2.0.2'
具体的转换过程就完成不需要我们来实现了。是不是很方便。
Post上传单个文件
还是先声明:
@Multipart @POST("rpostSingerFile") Call<ResponseBody> uploadSingerFile(@Part MultipartBody.Part mPhoto, @Part("user")RequestBody user,@Part("passwd") RequestBody passwd);
这里@MultiPart的意思就是允许多个@Part了,我们这里使用了3个@Part,第一个我们准备上传个文件,使用了MultipartBody.Part类型,其余两个均为简单的键值对。
使用:
File file = new File(Environment.getExternalStorageDirectory(),"test.jpg"); if(!file.exists()){ Log.e("TAG","file is not exit!"); return ; } RequestBody photoRequestBody = RequestBody.create(MediaType.parse("application/octet-stream"), file); MultipartBody.Part photo = MultipartBody.Part.createFormData("mPhoto", "test.jpg", photoRequestBody); Call<ResponseBody> call = repo.uploadSingerFile(photo, RequestBody.create(null, "abc"), RequestBody.create(null, "123")); executeByEn(call);
代码形式和前面的Okhttp基本差不多。
Post上传多个文件:
这里可能和服务端实际接收的代码有关,我这里是用了一种简单的方法来接收多个文件。服务端的代码如下:
public List<File> image; // 上传的文件 public List<String> imageFileName; // 文件名称 public List<String> imageContentType; // 文件类型 //上传图片 public String upLoadMulitFile() throws IOException{ ServletActionContext.getRequest().setCharacterEncoding("UTF-8"); System.out.println("开始接收文件"); String dir = ServletActionContext.getServletContext().getRealPath("files"); // 取得需要上传的文件数组 List<File> files = image; if (files != null && files.size() > 0) { System.out.println("image ="+image.get(0).getName()); for (int i = 0; i < files.size(); i++) { FileOutputStream fos = new FileOutputStream(dir + "\\" + imageFileName.get(i)); FileInputStream fis = new FileInputStream(files.get(i)); byte[] buffer = new byte[1024]; int len = 0; while ((len = fis.read(buffer)) > 0) { fos.write(buffer, 0, len); } fis.close(); fos.close(); } } return null; }
客服端我们是这么写的。:
@Multipart @POST("rpostMulitFile") Call<ResponseBody> upload(@Part()List<MultipartBody.Part> parts);
使用:
File file1 = new File(Environment.getExternalStorageDirectory(),"test.jpg"); File file2 = new File(Environment.getExternalStorageDirectory(),"test.JPEG"); RequestBody photoRequestBody1 = RequestBody.create(MediaType.parse("application/octet-stream"), file1); RequestBody photoRequestBody2 = RequestBody.create(MediaType.parse("application/octet-stream"), file2); MultipartBody.Part photo1 = MultipartBody.Part.createFormData("image", "test22.jpg", photoRequestBody1); MultipartBody.Part photo2 = MultipartBody.Part.createFormData("image", "test33.jpg", photoRequestBody2); List<MultipartBody.Part> parts = new ArrayList<>(); parts.add(photo1); parts.add(photo2); Call<ResponseBody> call = repo.upload(parts); executeByEn(call);
其实还有很多可优化的余地,只是当作demo,学习,就并没有使用跟好的写法。比如鸿洋大神是这么干的。
public interface IUserBiz { @Multipart @POST("register") Call<User> registerUser(@PartMap Map<String, RequestBody> params, @Part("password") RequestBody password);}
执行的代码:
File file = new File(Environment.getExternalStorageDirectory(), "messenger_01.png"); RequestBody photo = RequestBody.create(MediaType.parse("image/png", file);Map<String,RequestBody> photos = new HashMap<>();photos.put("photos\"; filename=\"icon.png", photo);photos.put("username", RequestBody.create(null, "abc"));Call<User> call = userBiz.registerUser(photos, RequestBody.create(null, "123"));
但是我并没有将其实现,可能是我服务端的代码限制了吧 。
下载
还是在IUserService中添加声明:
@GET("files/test.jpg") Call<ResponseBody> download();
执行:
Call<ResponseBody> call = repo.download(); call.enqueue(new Callback<ResponseBody>() { @Override public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) { //save file in here Log.d("TAG","downFile..."); InputStream is = response.body().byteStream(); int len; try { File file = new File(Environment.getExternalStorageDirectory(),"download.jpg"); FileOutputStream fos = new FileOutputStream(file); byte[] buf = new byte[128]; while( (len=is.read(buf)) != -1) { fos.write(buf, 0, len); } fos.flush(); fos.close(); is.close(); } catch (IOException e) { e.printStackTrace(); } Log.d("TAG","down success!"); } @Override public void onFailure(Call<ResponseBody> call, Throwable t) { } });
也比较简单吧。不过对象OkHttp好像也没有特别大的优势。
OkHttp的写法是这样的:
Request.Builder builder = new Request.Builder(); Request request = builder.get().url(BASE_URL+"files/test2.jpg").build(); okhttp3.Call call = okHttpClient.newCall(request); call.enqueue(new Callback() { @Override public void onFailure(okhttp3.Call call, IOException e) { Log.e("TAG","Error"+e); } @Override public void onResponse(okhttp3.Call call, Response response) throws IOException { //保存到本地, downSavetoFile(response); } });
当然,这些都只是一些比较简单的用法,也算是比较核心的用法了。接下来我们要学的可能就是细节上的设置和一些优化、封装等等了。暂时先告一段落吧~。明天看看还能能不能更一篇。
最后,有需要源代码的,可以戳这里。
五一快乐~~~。
- Retrofit使用入门
- Retrofit使用入门
- Retrofit-入门使用
- Retrofit网络框架入门使用
- Retrofit简单入门及使用
- Retrofit使用教程(一)- Retrofit入门详解
- Retrofit使用教程(一)- Retrofit入门详解
- 简单入门使用Retrofit+ rxjava 下载图片
- 网络请求框架 Retrofit 2 使用入门
- Retrofit入门
- retrofit入门
- Retrofit入门
- Retrofit入门
- Retrofit使用
- Retrofit使用
- Retrofit使用
- Retrofit使用
- Retrofit使用
- mysql5.7解压版安装
- 一行代码改进NMS
- 在 Android 上使用 VIPER 架构
- task_struct结构体
- NUC1019 数素数【素数筛选法】
- Retrofit使用入门
- nginx的安装与配置(linux)
- 清除 thinkphp跟php的 X-Powered-By
- HDU3966 树链剖分
- Android setPixel抛出java.lang.IllegalStateException
- Codeforces Round #400 (Div. 1 + Div. 2, combined)C. Molly's Chemicals
- reactNative底部导航菜单栏实现
- 16山东省赛B题SDNU1504
- C(1908)The Big Escape