zoukankan      html  css  js  c++  java
  • 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-x64apache-tomcat-7.0.94,然后点击finsih即可。

    5.4.解压struts文件,并将E:struts-2.3.24.1-allstruts-2.3.24.1appsstruts2-blankWEB-INFlib目录下的所有jar包复制到你刚才创建的web项目的WEB-INFlib下,并将E:struts-2.3.24.1-allstruts-2.3.24.1appsstruts2-blankWEB-INFclasses目录下的struts.xml文件复制到你刚才创建的web项目的src下即可,然后打开struts.xml文件,将其中的 两个filtter复制到你web项目的web.xml文件中,两个filtter:
    <filter>
            <filter-name>struts2</filter-name>
            <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
        </filter>
    
        <filter-mapping>
            <filter-name>struts2</filter-name>
            <url-pattern>/*</url-pattern>
        </filter-mapping>

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

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE struts PUBLIC
    	"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
    	"http://struts.apache.org/dtds/struts-2.3.dtd">
    
    <struts>
        <constant name="struts.enable.DynamicMethodInvocation" value="true" />
        <constant name="setruts.devMode" value="true" />
        <package name="default" namespace="/" extends="struts-default">
        </package>
    </struts>

    服务器端搭建完毕!

    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文件,修改成如下:

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE struts PUBLIC
    	"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
    	"http://struts.apache.org/dtds/struts-2.3.dtd">
    
    <struts>
        <constant name="struts.enable.DynamicMethodInvocation" value="true" />
        <constant name="struts.devMode" value="true" />
        <package name="default" namespace="/" extends="struts-default">
        <action name="Login" class="com.okhttp.UserAction" method="Login"></action>
        </package>
        <!--name="Login"是你在浏览器端访问时的名字,class是对应包名,method是指至该class中对应的Login方法,这样就完成了映射 -->
    </struts>

    然后将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文件中添加 
            // <uses-permission android:name="android.permission.INTERNET"></uses-permission>即可
        }

    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-x64lib目录下的  servlet-api.jar,导入方法1.右键你的项目——》2.build path——》3.configure build path——》4.add External Jars——》5.找到E:apache-tomcat-7.0.94-windows-x64lib的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");
         //需要在模拟器中存放一张照片,并添加权限
            //<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
            //还需要再模拟器设置权限中手动打开该客户端项目的权限
           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文件

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE struts PUBLIC
    	"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
    	"http://struts.apache.org/dtds/struts-2.3.dtd">
    
    <struts>
        <constant name="struts.enable.DynamicMethodInvocation" value="true" />
        <constant name="struts.devMode" value="true" />
        <package name="default" namespace="/" extends="struts-default">
        <action name="Login" class="com.okhttp.UserAction" method="Login"></action>
        <action name="PostString" class="com.okhttp.UserAction" method="PostString"></action>
        <action name="PostFile" class="com.okhttp.UserAction" method="PostFile"></action>
        <action name="UploadInfo" class="com.okhttp.UserAction" method="UploadInfo"></action>
        </package>
        
    </struts>

    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");
         //需要在模拟器中存放一张照片,并添加权限
            //<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
            //还需要再模拟器设置权限中手动打开该客户端项目的权限
           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
  • 相关阅读:
    hdu 6836
    2019 树形—DP
    2020牛客暑期多校训练营(第六场)
    hdu 6756 Finding a MEX 线段树
    2020 Multi-University Training Contest 2
    spring boot maven 打jar包 不能引入外部jar
    git 操作命令
    homestead 安装swoole
    MYSQL-触发器
    再次认知const
  • 原文地址:https://www.cnblogs.com/hzcya1995/p/13309545.html
Copyright © 2011-2022 走看看