Android-Okhttp的使用解析
okhttp是Android6.0推出的网络框架。由于谷歌在Android6.0的之后,将HttpClient相关属性取消掉,导致Volley框架不能正常使用。所以才有了今天的Okhttp。
Okhttp进行网络访问通常有两种方式,一种是get请求,还有一种叫做post请求。
1、OKhttp的get请求
通常,我们使用get方式来请求一个网站,是依靠url地址的。Okhttp使用get方式来请求网站通常有如下的步骤:
A、创建OkhttpClient的变量,这个变量相当于是一个全局的执行者。主要的网络操作是依靠它来进行的。
B、创建一个builder对象。
C、利用builder对象创建一个Request对象。
D、使用全局执行者来创建一个Call对象。
E、通过Call对象来进行网络连接。
public void doGet(View view) { Request.Builder builder = new Request.Builder(); Request request = builder.get().url(urlString + "userName=pby&userPassword=123").build(); Call newCall = mOkHttpClient.newCall(request); //newCall.execute() newCall.enqueue(new Callback() { @Override public void onFailure(Request request, IOException e) { L.e("失败了"); } @Override public void onResponse(Response response) throws IOException { String string = response.body().string(); L.e(string); } }); }
2、Okhttp的Post请求
Post请求与get请求有些不一样。get请求主要的功能是从服务器上获取数据,而Post请求则是向服务器提交数据。
public void doPost(View view) { FormEncodingBuilder requestBodyBuilder = new FormEncodingBuilder(); RequestBody requestBody = requestBodyBuilder.add("userName", "pby").add("userPassword", "123").build(); Request.Builder builder = new Request.Builder(); Request request = builder.url(urlString).post(requestBody).build(); Call newCall = mOkHttpClient.newCall(request); executeCall(newCall); }
3、服务器端接收客户端传过来的字符串
客户端的代码:
public void doPostString(View view) { RequestBody requestBody = RequestBody.create(MediaType.parse("text/plain;charset = utf-8"), "{name = pby, password = 1234}"); Request.Builder builder = new Request.Builder(); Request request = builder.url(urlString + "doPostString").post(requestBody).build(); Call newCall = mOkHttpClient.newCall(request); executeCall(newCall); }
服务器端的代码:
public String doPostString() throws IOException { HttpServletRequest request = ServletActionContext.getRequest(); ServletInputStream inputStream = request.getInputStream(); StringBuilder sb = new StringBuilder(); int len = 0; byte []buff = new byte[1024]; while((len = inputStream.read(buff)) != -1) { sb.append(new String(buff, 0, len)); } System.out.println(sb.toString()); return null; }
服务器端如果要接收客户端的数据,则需要接收request;如果服务器端想要给客户端传数据,则需要通过response来传递。
4、使用post方式进行文件的传输
客户端的代码
public void doPost(View view) { FormEncodingBuilder requestBodyBuilder = new FormEncodingBuilder(); RequestBody requestBody = requestBodyBuilder.add("userName", "pby").add("userPassword", "123").build(); Request.Builder builder = new Request.Builder(); Request request = builder.url(urlString + "login").post(requestBody).build(); Call newCall = mOkHttpClient.newCall(request); executeCall(newCall); }
关于选择文件的代码--抄袭网络上的代码,并不是自己写的
private void showFileChooser() { Intent intent = new Intent(Intent.ACTION_GET_CONTENT); intent.setType("*/*"); intent.addCategory(Intent.CATEGORY_OPENABLE); try { startActivityForResult( Intent.createChooser(intent, "Select a File to Upload"), 1); } catch (android.content.ActivityNotFoundException ex) { Toast.makeText(this, "Please install a File Manager.", Toast.LENGTH_SHORT).show(); } } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { switch (requestCode) { case 1: if (resultCode == RESULT_OK) { // Get the Uri of the selected file Uri uri = data.getData(); String path = FileUtils.getPath(this, uri); if(path != null) { postFile(path); } } break; } super.onActivityResult(requestCode, resultCode, data); }
在进行这个的操作的时候,一定要记住增加读和写的权限,否则会上传失败的。
服务器端的代码
public String doPostFile() throws IOException { HttpServletRequest request = ServletActionContext.getRequest(); ServletInputStream inputStream = request.getInputStream(); String dir = ServletActionContext.getServletContext().getRealPath("files"); File file = new File(dir, "abc.jpg"); FileOutputStream fos = new FileOutputStream(file); int len = 0; byte [] buff = new byte[1024]; while((len = inputStream.read(buff)) != -1) { fos.write(buff, 0, len); } fos.flush(); fos.close(); return null; }
上面显示的files文件,在Tomcat的webapps下的工程名名文件下的fies文件夹(才开始是没有这个文件夹的,需要手动自己创建)。
5.使用Post方式来上传文件
客户端代码:
private void upLoadFile(String path) { File file = new File(path); if(!file.exists()) { return ; } MultipartBuilder multipartBuilder = new MultipartBuilder(); RequestBody requestBody = multipartBuilder.type(MultipartBuilder.FORM) .addFormDataPart("userName", "pby") .addFormDataPart("userPassword", "123") .addFormDataPart("mFile", file.getName(), RequestBody.create(MediaType.parse("application/octet-stream"), file)).build(); // CountingRequestBody countingRequestBody = new CountingRequestBody(requestBody, new CountingRequestBody.MyListener() { // @Override // public void onRequestProgress(int byteWriteCount, int TotalCount) { // L.e(byteWriteCount + " / " + TotalCount); // } // }); Request.Builder builder = new Request.Builder(); //Request request = builder.url(urlString + "doUpLoadFile").post(countingRequestBody).build(); Request request = builder.url(urlString + "doUpLoadFile").post(requestBody).build(); Call newCall = mOkHttpClient.newCall(request); executeCall(newCall); }
服务器端的代码:
public String doUpLoadFile() { if(mFile == null) { System.out.println(mFileFileName+" is null.."); return null; } String dir = ServletActionContext.getServletContext().getRealPath("files"); File file = new File(dir, mFileFileName); try { FileUtils.copyFile(mFile, file); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } return null; }
在上传文件的时候,有一个小细节都注意到:就是Tomcat服务器只允许上传2m以下的文件。要想上传大文件,就必须在struct文件中加一句:<constant name="struts.multipart.maxSize" value="1024000000"/>数字表示自定义大小的限制。
6.上传文件时,进度的显示问题
在写代码的时候我们知道,我们不能直接获得上传文件的进度。因为这些数据都是封装在RequestBody里面的,要想使用只有通过回调接口来实现。
package com.example.android_okhttp; import com.squareup.okhttp.MediaType; import com.squareup.okhttp.RequestBody; import java.io.IOException; import okio.Buffer; import okio.BufferedSink; import okio.ForwardingSink; import okio.Okio; import okio.Sink; /** * Created by 前世诀别的一纸书 on 2017/3/5. */ public class CountingRequestBody extends RequestBody { private RequestBody delegate = null; private MyListener mListener= null; private CountingSink mCountSink = null; public interface MyListener { void onRequestProgress(int byteWriteCount, int TotalCount); } public CountingRequestBody(RequestBody requestBody, MyListener listener) { delegate = requestBody; mListener = listener; } @Override public MediaType contentType() { return delegate.contentType(); } @Override public void writeTo(BufferedSink sink) throws IOException { mCountSink = new CountingSink(sink); BufferedSink bs = Okio.buffer(mCountSink); delegate.writeTo(bs); bs.flush(); } private class CountingSink extends ForwardingSink{ private int byteWriteCount = 0; public CountingSink(Sink delegate) { super(delegate); } @Override public void write(Buffer source, long byteCount) throws IOException { super.write(source, byteCount); byteWriteCount += byteCount; mListener.onRequestProgress(byteWriteCount, (int) contentLength()); } } @Override public long contentLength() throws IOException { return delegate.contentLength(); } }
MultipartBuilder multipartBuilder = new MultipartBuilder(); RequestBody requestBody = multipartBuilder.type(MultipartBuilder.FORM) .addFormDataPart("userName", "pby") .addFormDataPart("userPassword", "123") .addFormDataPart("mFile", file.getName(), RequestBody.create(MediaType.parse("application/octet-stream"), file)).build(); CountingRequestBody countingRequestBody = new CountingRequestBody(requestBody, new CountingRequestBody.MyListener() { @Override public void onRequestProgress(int byteWriteCount, int TotalCount) { L.e(byteWriteCount + " / " + TotalCount); } }); Request.Builder builder = new Request.Builder(); Request request = builder.url(urlString + "doUpLoadFile").post(countingRequestBody).build(); //Request request = builder.url(urlString + "doUpLoadFile").post(requestBody).build(); Call newCall = mOkHttpClient.newCall(request);