【Android】Okhttp的使用总结(前端后端详述)

引言

该篇博客主要对Okhttp的几种使用方法做总结,包括get,post,上传文件,下载文件。

一.Okhttp重要内容梳理

1.OkHttpClient: OkHttp请求的客户端类,核心地位,很多功能主要靠OkhttpClent来转发和实现,他的创建方法有两种

1.1).默认的通过new一个对象来实例化,如:

OkhttpClient okhttpclient=new OkhttpClient();

1.2).通过构建者模式Builder创建,如

OkhttpClient okhttpclient=new OkhttpClient.Builder().build();

1.3).说明:现实中网络情况是比较复杂的,需要考虑的设置一些参数,如设置超时时间,readTimeout也可以通过设置okhttoClient对象来实现,如

OkHttpClient okHttpClient=new OkHttpClient.Builder().readTimeout(5000,TimeUnit.MILLISECONDS)
.build();




2.Request:主要用来设置请求报文类的相关信息,如Url,请求方式以及请求头等。
2.1).默认的通过new一个对象来实例化,与OkhttpClient的创建方法相同,如

Request request=new Request()

2.2).通过构建者模式设置,如

Request request=new Request.Builder().build();

2.3).说明:我们需要给request设置一些参数,如请求地址方式等

Request request=new Request.Builder().post(requestBody).url(“http://xxxx.com”).build();
Request request=new Request.Builder().get().url(“http://xxxx.com”).build();

2.4).补充:post请求方式需要传入RequestBody对象,后面会说。



3.Call:他实际上代表了一个待执行的http请求,可以理解为连接request和response 的一个桥梁。
2.1).创建call对象的方式与okhttpclient和request不同,如:

Call call=okhttpclient.newCall(request);//其中okhttpclient和request是之前创建好的对象

2.2).说明:newCall方法实际上是空的,返回的是RealCall.newCall(request),关于源码分析的详情可以看相关视频。

2.3).同步请求与异步请求

Response response = call.execute();;//同步请求,会阻塞当前线程,直到请求返回结果,reponse是返回结果
call.enqueue(new CallBack());//异步请求,开启子线程执行,不会阻塞当前线程。CallBack是一个回调接口,当请求产生结果时被调用

2.4)关于CallBack

/*改回调在子线程执行,所以不可以在其中更新UI,可以使用runOnUiThread;来更新UI,如下*/
call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
            //onFailure当请求发生异常或请求失败时调用
                L.e("onFailure:"+e.getMessage());
            }
            @Override
            public void onResponse(Call call, final Response response) throws IOException {
            //请求成功时调用
               // InputStream is = response.body().byteStream();获得请求返回的字节流
               String res=reponse.body().String();//服务器返回的信息
               runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        textView.setText(res);
                    }
                });
            }
        });

4.小结
4.1.一个最简单的Okhttp使用分为三步

4.1.1).创建OkhttpCilent和requset对象
4.1.2).创建Call对象
4.1.3).执行Call对象,发起同步或异步请求并处理返回数据

4.2.同步请求与异步请求的区别:
4.2.1.发起请求时的方法调用不同;
4.2.2.同步阻塞当前线程,异步开启子线程执行,不阻塞当前线程
4.2.3.内部实现:excute()方法将该请求推入执行队列,enqueue()方法则需要经过处理加入准备执行队列,其内部实现有很大的区别。

补充:本篇只对OkhttpClient的使用做说明,其中详细的实现机制如dispatcher分发器,connectpool连接池以及getResponseIncepterChain等重要的机制需要自己去看源码!(也有相关讲解视频,有需要联系我)

二.搭建服务器端

建议:将下载的tomcat,struts放在E盘下,这样就可以参考我的路径配置!
5.1.tomcat.struts框架的下载
云盘地址:链接: https://pan.baidu.com/s/1jkYVw6Flm8sLJknn5ZjAXg 提取码: 9wba 复制这段内容后打开百度网盘手机App,操作更方便哦

5.2.Eclipse下新建Web项目,1.File——》2.Dynamic Web project——》3.填写项目名称:Okhttp(可自定义)

5.3.配置tomcat,1.Eclipse下的window按钮——》2.选择Preference——》3.搜索Server——》4.选择runtime environment——》5.点击Add按钮——》6.选择你要配置的tomcat版本——》7.点击next——》8.name不需要修改,修改tomcat installation dir,将你下载好的tomcat包解压,放在适合的位置后,一定要选择最后一个带编号的apache文件夹点进去,如我的路径E:\apache-tomcat-7.0.94-windows-x64\apache-tomcat-7.0.94,然后点击finsih即可。

5.4.解压struts文件,并将E:\struts-2.3.24.1-all\struts-2.3.24.1\apps\struts2-blank\WEB-INF\lib目录下的所有jar包复制到你刚才创建的web项目的WEB-INF\lib下,并将E:\struts-2.3.24.1-all\struts-2.3.24.1\apps\struts2-blank\WEB-INF\classes目录下的struts.xml文件复制到你刚才创建的web项目的src下即可,然后打开struts.xml文件,将其中的 两个filtter复制到你web项目的web.xml文件中,两个filtter:
 
        struts2
        org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter
    

    
        struts2
        /*
    

如果你的web项目没有web.xml右键你的项目然后选择JavaEE tools——》generate…即可;
然后修改struts.xml文件成如下状态:





    
    
    
    


服务器端搭建完毕!

5.5.测试服务器端
1.首先在web端的src目录下新建一个包:com.okhttp,在该包中新建一个UserAction.java文件,代码如下:

package com.okhttp;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
//有些包是这一步不需要导入的可以忽略
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.io.FileUtils;
import org.apache.struts2.ServletActionContext;
import com.opensymphony.xwork2.ActionSupport;

public class UserAction extends ActionSupport {
//ActionSupport是框架内提供的一个类,非常便捷
	private String username;//用户名
	private String password;//密码
	public String Login() throws IOException
	{
		
		System.out.println(username+" "+password);
		//直接打印username和password
	   return null;
		
	}
	public String getUsername() {
		return username;
	}
	public void setUsername(String username) {
		this.username = username;
	}
	public String getPassword() {
		return password;
	}
	public void setPassword(String password) {
		this.password = password;
	}
	

}

代码写完以后,我们需要去映射这个方法,打开struts.xml文件,修改成如下:





    
    
    
    
    
    

然后将web项目运行起来,选择刚才配置的tomcat即可,在浏览器上输入
localhost:8080//项目名/Login?username=xxx&password=123;
观察Eclipse控制台有无输出,有输出说明配置成功,若无输出看日志找错误

三.OkHttp的使用

准备工作:由于我们是在本地方法,在模拟器上不知道localhost是什么,先通过cmd控制台输入ipconfig/all,查询你的localhost地址即是你的Ipv4地址,每一个请求都是通过一个按钮来发起的,所以每一种新的请求方法,都需要新建一个button,添加OnClick="xxxx",并在Activity中创建出来,布局代码不再说明,后面不再做说明

6.1.get请求代码
 public void Doget(View view) throws IOException {

        Request.Builder builder=new Request.Builder();
        final Request request = builder.get().url(mBaseUrl+"Login?username=Yang&password=123").build();
        //mBaseurl是全局变量即“http://IPv4/项目名/”
        //okhttpclient也是全局变量,只需要创建即可,无需其他设置
        Call call=okHttpClient.newCall(request);
        Response response = call.execute();
        //执行后查看Eclipse 控制台的输出,这一步需要允许网络权限,在AndroidManifest.xml文件中添加 
        // 即可
    }

6.2.添加web端的响应代码,即客户端发出请求后,服务器返回响应信息:
将刚才web端的Login()方法修改成如下:

public String Login() throws IOException
	{
		
		System.out.println(username+" "+password);
		HttpServletResponse response=ServletActionContext.getResponse();
		PrintWriter writer=response.getWriter();
		writer.write("Login Success!");
		writer.flush();
		return null;
		
	}

客户端修改成如下:

 public void Doget(View view) throws IOException {

        Request.Builder builder=new Request.Builder();
        final Request request = builder.get().url(mBaseUrl+"Login?username=Yang&password=123").build();
        Call call=okHttpClient.newCall(request);
        Response response = call.execute();
        String res=response.body().String();
        Log.d("Response",res);
      
    }

再次发起请求,观察Android logcat下的日志有无Login success!,到这一步已经打通客户端与服务器端的响应!

6.3.Post请求
客户端代码如下:

 public void Dopost(View view) throws IOException {
        FormBody requestbuilder=new FormBody.Builder().add("username", "Yang")
                .add("password", "123456").build();
                //FormBody的简单用法,可理解为键值对
        Request request=new Request.Builder().post(requestbuilder).url(mBaseUrl+"Login").build();
        ExcuteRequest(request);//该方法用来处理返回信息
       
    }
     private void ExcuteRequest(Request request) throws IOException {
        Call call=okHttpClient.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                L.e("onFailure:"+e.getMessage());
            }
            @Override
            public void onResponse(Call call, final Response response) throws IOException {
                final String res=response.body().string();
                L.e("onResponse:"+res);
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        textView.setText(res);//在界面上添加了一个textview用来显示响应信息
                    }
                });
            }
        });
    }

6.4.PostString
改动web端,新增加PostString()方法,代码如下:
每次新建方法以后,不要忘记添加该方法的映射,并重新运行web项目

public String PostString() throws IOException
	{
		
		HttpServletRequest request=ServletActionContext.getRequest();
		ServletInputStream is=request.getInputStream();
        //HttpServletRequest 类如果没有被导入,需要手动导入E:\apache-tomcat-7.0.94-windows-x64\lib目录下的  servlet-api.jar,导入方法1.右键你的项目——》2.build path——》3.configure build path——》4.add External Jars——》5.找到E:\apache-tomcat-7.0.94-windows-x64\lib的servlet-api.jar文件导入即可
		StringBuilder sb=new StringBuilder();
		byte[] buf=new byte[1024];
		int len=0;
		while((len=is.read(buf))!=-1) {
			sb.append(new String(buf,0,len));
		}
		System.out.println(sb.toString());
		return null;
	}

客户端代码

 public void DopostString(View view) throws IOException {
        RequestBody requestBody = RequestBody.create("{username:xxx,password:123456789}"
                , MediaType.parse("text/plain;charset=utf-8"));
                //构建一个requestBody
        Request request=new Request.Builder().post(requestBody).url(mBaseUrl+"PostString").build();
        ExcuteRequest(request);
    }

6.5.PostFile
web端新建postFile方法,别忘了添加映射,重新运行,代码如下

	public String PostFile() throws IOException
	{
		
		HttpServletRequest request=ServletActionContext.getRequest();
		ServletInputStream is=request.getInputStream();
		String dir=ServletActionContext.getServletContext().getRealPath("files");
		System.out.println(dir+"----------------");
		File file=new File(dir,"陈.jpg");
		//dir是保存图片的路径
		//"陈.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;
	}

客户端代码:

public void PostFile(View view) throws IOException {
     File  file=new File(Environment.getExternalStorageDirectory(),"陈.jpg");
     //需要在模拟器中存放一张照片,并添加权限
        //
        //还需要再模拟器设置权限中手动打开该客户端项目的权限
       if(!file.exists()){
           L.e("File not exists!");
           //此处的L是自己写的一个方法,可用Log代替,不必在意
           return;
       }else{

           RequestBody requestBody = RequestBody.create(file
                   , MediaType.parse("application/octet-stream"));
           Request request=new Request.Builder().post(requestBody).url(mBaseUrl+"PostFile").build();
           ExcuteRequest(request);
       }
    }

6.6还有上传表单等,以及下载文件,不再单独说明,以下是总的服务器端和客户端代码
web端

package com.okhttp;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.io.FileUtils;
import org.apache.struts2.ServletActionContext;

import com.opensymphony.xwork2.ActionSupport;

public class UserAction extends ActionSupport {
	private String username;
	private String password;
	public File mPhoto;
	public String mPhotoFileName;
	public String UploadInfo() throws IOException
	{
		if(mPhoto==null) {
			System.out.println("Photo not exist!");
		}else {
			String dir=ServletActionContext.getServletContext().getRealPath("files");
			File file=new File(dir,mPhotoFileName);
			System.out.println(username+"------------------"+password);
			FileUtils.copyFile(mPhoto,file);
		}
		return null;
	}
	
	public String PostFile() throws IOException
	{
		
		HttpServletRequest request=ServletActionContext.getRequest();
		ServletInputStream is=request.getInputStream();
		String dir=ServletActionContext.getServletContext().getRealPath("files");
		System.out.println(dir+"----------------");
		File file=new File(dir,"陈.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;
	}
	public String PostString() throws IOException
	{
		
		HttpServletRequest request=ServletActionContext.getRequest();
		ServletInputStream is=request.getInputStream();

		StringBuilder sb=new StringBuilder();
		byte[] buf=new byte[1024];
		int len=0;
		while((len=is.read(buf))!=-1) {
			sb.append(new String(buf,0,len));
		}
		System.out.println(sb.toString());
		return null;
	}
	public String Login() throws IOException
	{
		
		System.out.println(username+" "+password);
		HttpServletResponse response=ServletActionContext.getResponse();
		PrintWriter writer=response.getWriter();
		writer.write("Login Success!");
		writer.flush();
		
		return null;
		
	}
	public String getUsername() {
		return username;
	}
	public void setUsername(String username) {
		this.username = username;
	}
	public String getPassword() {
		return password;
	}
	public void setPassword(String password) {
		this.password = password;
	}
	

}

struts.xml文件





    
    
    
    
    
    
    
    
    


OkhttpClientActivity.java

package com.example.yang.crazydemo;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Environment;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import Java.L;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.FormBody;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;

public class OkhttpActivity extends AppCompatActivity {
private TextView textView;
private String mBaseUrl="http://47.106.141.161/Okhttp/";
private  OkHttpClient okHttpClient=new OkHttpClient();
private File file;
private ImageView imageView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_okhttp);
        textView=findViewById(R.id.text);
        file=new File(Environment.getExternalStorageDirectory(),"陈.jpg");
        imageView=findViewById(R.id.img);



    }
    public void Doget(View view) throws IOException {

        Request.Builder builder=new Request.Builder();
        final Request request = builder.get().url(mBaseUrl+"Login?username=Yang&password=123").build();
        //ExcuteRequest(request);
        Call call=okHttpClient.newCall(request);
        Response response = call.execute();

    }

    private void ExcuteRequest(Request request) throws IOException {
        Call call=okHttpClient.newCall(request);
        call.execute();
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                L.e("onFailure:"+e.getMessage());
            }

            @Override
            public void onResponse(Call call, final Response response) throws IOException {
                final String res=response.body().string();
                L.e("onResponse:"+res);
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        textView.setText(res);
                    }
                });
            }
        });
    }

    public void Dopost(View view) throws IOException {
        FormBody requestbuilder=new FormBody.Builder().add("username", "Yang")
                .add("password", "123456").build();
        Request request=new Request.Builder().post(requestbuilder).url(mBaseUrl+"Login").build();
        ExcuteRequest(request);
    }

    public void DopostString(View view) throws IOException {
        RequestBody requestBody = RequestBody.create("{username:yang,password:123456789}"
                , MediaType.parse("text/plain;char0set=utf-8"));
        Request request=new Request.Builder().post(requestBody).url(mBaseUrl+"PostString").build();
        ExcuteRequest(request);
    }

    public void PostFile(View view) throws IOException {
     File  file=new File(Environment.getExternalStorageDirectory(),"陈.jpg");
     //需要在模拟器中存放一张照片,并添加权限
        //
        //还需要再模拟器设置权限中手动打开该客户端项目的权限
       if(!file.exists()){
           L.e("File not exists!");
           //此处的L是自己写的一个方法,可用Log代替,不必在意
           return;
       }else{

           RequestBody requestBody = RequestBody.create(file
                   , MediaType.parse("application/octet-stream"));
           Request request=new Request.Builder().post(requestBody).url(mBaseUrl+"PostFile").build();
           ExcuteRequest(request);
       }
    }

    public void doUpload(View view) throws IOException {
    //上传表单信息,包括文字和图片
        RequestBody requestBody = RequestBody.create(file
                , MediaType.parse("application/octet-stream"));
        MultipartBody build = new MultipartBody.Builder().setType(MultipartBody.FORM)
                .addFormDataPart("username", "yang")
                .addFormDataPart("password", "yang123")
                .addFormDataPart("mPhoto", "Yang.jpg",requestBody).build();
        Request request=new Request.Builder().post(build).url(mBaseUrl+"UploadInfo").build();
        ExcuteRequest(request);
    }

    public void doDownload(View view) {
    //下载文件
        Request.Builder builder=new Request.Builder();
        final Request request = builder.get().url(mBaseUrl+"files/Yang.jpg").build();
        Call call=okHttpClient.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                L.e("onFailure:"+e.getMessage());
            }
            @Override
            public void onResponse(Call call, final Response response) throws IOException {
                InputStream is = response.body().byteStream();

                int len=0;
                byte[] buf=new byte[128];
                File file = new File(Environment.getExternalStorageDirectory(),"Cheng.jpg");
                L.e(Environment.getExternalStorageDirectory().toString());
                FileOutputStream fileOutputStream = new FileOutputStream(file);
                //输出流
                while((len=is.read(buf))!=-1){
                    fileOutputStream.write(buf,0,len);
                }
                fileOutputStream.flush();
                fileOutputStream.close();
                is.close();
            }
        });
    }

    public void doDownloadImg(View view) {
//将图片显示在Imageview上
        Request.Builder builder=new Request.Builder();
        final Request request = builder.get().url(mBaseUrl+"files/Yang.jpg").build();
        Call call=okHttpClient.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                L.e("onFailure:"+e.getMessage());
            }
            @Override
            public void onResponse(Call call, final Response response) throws IOException {
                InputStream is = response.body().byteStream();
                final Bitmap bitmap=BitmapFactory.decodeStream(is);
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        imageView.setImageBitmap(bitmap);
                    }
                });
            }
        });
    }
}



四.OkHttp的总结

okhttp是一个优秀的网络框架,其内部实现的机制如拦截链和分发器等,设计很巧妙,想要学会基本使用不难,难得是理解内部实现原理,感谢你阅读该博客,如果有问题可以联系QQ:2460228341

你可能感兴趣的:(Android,Okhttp,服务器搭建)