Android学习笔记(十九) OkHttp

一、概述

根据我的理解,OkHttp是为了方便访问网络或者获取服务器的资源,而封装出来的一个工具包。通常的使用步骤是:首先初始化一个OkHttpClient对象,然后使用builder模式构造一个Request,之后使用Call来执行这个Request。其中,OkHttpClient一般只使用一个,而OkHttpClient的newCall方法则对应每次请求的执行。

二、Get

2.1 步骤分解

  1. 拿到OkHttpClient对象
  2. 构造Request
  3. 将Request封装为Call
  4. 执行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 步骤分解

  1. 拿到OkHttpClient对象
  2. 构造RequestBody
  3. 构造Request
  4. 将Request封装为Call
  5. 执行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!");
}
posted @ 2017-04-11 19:34  viaduct  阅读(225)  评论(0编辑  收藏  举报