Android学习笔记(十九) OkHttp
一、概述
根据我的理解,OkHttp是为了方便访问网络或者获取服务器的资源,而封装出来的一个工具包。通常的使用步骤是:首先初始化一个OkHttpClient对象,然后使用builder模式构造一个Request,之后使用Call来执行这个Request。其中,OkHttpClient一般只使用一个,而OkHttpClient的newCall方法则对应每次请求的执行。
二、Get
2.1 步骤分解
- 拿到OkHttpClient对象
- 构造Request
- 将Request封装为Call
- 执行Call(直接execute或者enqueue)
2.2 程序
public void doGet(View view) throws IOException{ OkHttpClient client = new OkHttpClient(); Request request = new Request.Builder().url("http://www.imooc.com/").build(); Call call = client.newCall(request); call.enqueue(new Callback(){ @Override public void onFailure(Call call, IOException e) { Log.e("okHttp",e.getMessage()); } @Override public void onResponse(Call call, Response response) throws IOException { Log.d("okHttp","doGet success!"); String string = response.body().string(); Log.d("okHttp Content",string); } }); }
上面的enqueue也可以换成execute,不过执行后返回一个Response对象。
相应代码替换成:
Response response = call.execute(); if(response.isSuccessful){ return response.body().string(); }else{ throw new IOException("Unexpected code " + response); }
三、Post键值对
3.1 步骤分解
- 拿到OkHttpClient对象
- 构造RequestBody
- 构造Request
- 将Request封装为Call
- 执行Call
3.2 代码
public void doPost(View view){ OkHttpClient client = new OkHttpClient(); RequestBody body = new FormBody.Builder().builder() .add("username","admin") .add("password","123") .build(); Request.Builder builder = new Request.Builder(); Request = builder.url(mBaseUrl+"login").post(body).build(); Call call = client.newCall(request); call.enqueue(new Callback(){ @Override public void onFailure(Call call, IOException e) { Log.e("okHttp",e.getMessage()); } @Override public void onResponse(Call call, Response response) throws IOException { Log.d("okHttp","doGet success!"); String string = response.body().string(); Log.d("okHttp Content",string); } }); }
Call那个步骤在多数程序中都会用到,所以最好是抽取成为一个函数。在服务器端使用的是struts2架构,因此需要添加一个action,在所需调用的函数中将username和password打印出来就能看到post上去的数据了。
四、Post JSON(字符串)
和上面的步骤唯一不同的是RequestBody的构造。这里使用的是RequestBody的静态方法create()。
RequestBody body = RequestBody.create(MediaType.parse("text/plain;charset=utf-8"),"{username:admin,password:123}");
在服务器端的函数代码为:
public String postString(){ 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()); return null; }
五、Post File
参考上面的代码,这里构造RequestBody也是调用它的静态方法create(),只不过参数改成了跟File相适应的。
重复代码已省去。至于MediaType参数,参考http://www.w3school.com.cn/media/media_mimeref.asp。
File file = new File(Environment.getExternalStorageDirectory(),"test.jpg"); if(!file.exists()){ Log.e("file error","not exist!"); return; } RequestBody body = RequestBody.create(MediaType.parse("application/octet-stream"),file);
服务器端的程序也和上面的程序大同小异,只不过改成用FileOutputStream来接受InputStream里面的数据,而不是上面的StringBuilder。
public String postFile(){ HttpServletRequest request = ServletActionContext.getRequest(); ServletInputStream is = request.getInputStream(); String dir= ServletActionContext.getServletContext().getRealPath("files"
); File file = new File(dir,"test.jpg"); FileOutputStream fos = new FileOutputStream(file); int len = 0; byte[] buf = new byte[1024]; while((len = is.read(buf)) != -1){ fos.write(buf, 0, len); } fos.flush(); fos.close(); return null; }
这里有个需要注意的地方,getRealPath得到的路径默认是tomcat下webapps中的项目文件夹下。因为每次重启服务器里面的文件都会被删除,所以我更改了路径:
<Context path="/VCloud" docBase="D:\Workspace\VCloudDir" debug="0" reloadable="true"/>
我把文件test.jpg放在D:\Workspace\VCloudDir\files下,然后在浏览器中输入localhost:8080/VCloud/files/test.jpg就能打开这个文件。
六、上传文件以及参数
使用MultipartBody的意义在于:传输文件的同时可以传输字段;可以指定文件名;可以一次上传多个文件。
代码仅展示RequestBody部分,其他部分和上面基本一致。
File file = new File(Environment.getExternalStorageDirectory(),"test.jpg"); RequestBody fileRequestBody = RequestBody.create(MediaType.parse("application/octet-stream"),file); MultipartBody.Builder multipartBuilder = new MultipartBody.Builder(); RequestBody body = multipartBuilder .type(MultipartBody.FORM) .addFormDataPart("username","admin") .addFormDataPart("password","123") .addFormDataPart("mPhoto","test.jpg",fileRequestBody) .build();
服务端部分:
public File mPhoto; public String mPhotoFileName;//注意写法是固定的 public String uploadInfo(){ if(mPhoto == null){ System.out.println(mPhotoFileName + " is null .); } String dir = ServletActionContext.getServletContext().getRealPath("files"); File file = new File(dir, mPhotoFileName); FileUtils.copyFile(mPhoto, file); return null; }
七、下载文件
和get方法类似,不同之处在于对得到的Response的处理,即onResponse里面的内容。
url就是文件地址,如localhost:8080/VCloud/files/test.jpg。
public void onResponse(Response response){ Log.d("onResponse","onResponse"); InputStream is = response.body().byteStream(); int len = 0; File file = new File(Environment.getExternalStorageDirectory(),"test.jpg"); byte[] buf = new byte[128]; FileOutputStream fos = new FileOutputStream(file); while((len = is.read(buf)) != -1){ fos.write(buf, 0, len); } fos.flush(); fos.close(); is.close(); Log.d("download","download success!"); }