okhttp协议的学习(详细,方方面面)

okhttp协议的学习

1.导入依赖:

implementation 'com.squareup.okhttp3:okhttp:4.2.2'

2.使用OKhttp发起get请求

1.创建一个活动,在其xml文件内编写:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".Activity.OkHttpActivity"
    android:orientation="vertical">

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="getrequest"
        android:textAllCaps="false"
        android:onClick="GetRequest"
        tools:ignore="OnClick" />
</LinearLayout>
2.在.java文件内编写
public class OkHttpActivity extends AppCompatActivity {

    public final static String TAG = "OkHttpActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_ok_http);
    }

    public void GetRequest(View view) {
        //首先要有一个客户端,类似于要有一个浏览器
        OkHttpClient okHttpClient = new OkHttpClient.Builder()
                //在此处设置时间,和Http协议中的一样
                .connectTimeout(100000, TimeUnit.MILLISECONDS)
                //记得一定要build
                .build();
        //创建请求内容
        final Request request = new Request.Builder()
                //设置请求方式
                .get()
                //设置URL
                .url("https://wanandroid.com/wxarticle/chapters/json")
                //这里也要build
                .build();
        //用client去创建请求内容
        Call task = okHttpClient.newCall(request);
        //进行异步请求
        task.enqueue(new Callback() {
            @Override
            public void onFailure(@NotNull Call call, @NotNull IOException e) {
                Log.d(TAG, "onFailure: " + e.toString());
            }

            @Override
            public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
                //这里获取返回的状态码。和HTTP协议是一样的,对比参考
                int code = response.code();
                if ((code == HttpURLConnection.HTTP_OK)) {
                    //这里的body就是请求到的内容了,是response.body
                    ResponseBody body = response.body();
                    //body是个对象,用body.string把它变成字符串,这里也要记得哦
                    Log.d(TAG, "onResponse: " + body.string());
                }
            }
        });
    }

代码的解释已经在注释中写的很详尽了,可以与HTTP协议做作对比。多用!多用!!熟能生巧!!!

3.在UI中显示从服务器返回的数据

1.创建一个活动,在其xml文件中编写:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".Activity.OkHttpActivity"
    android:orientation="vertical">

    <Button
        android:id="@+id/btn"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="getrequest"
        android:textAllCaps="false"
        tools:ignore="OnClick" />

    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <TextView
            android:id="@+id/text_okhttp"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
    </ScrollView>
</LinearLayout>

具体什么用呢?就是想要实现一个点击按钮,然后下方出现从服务器获取到的数据。

2. 在.java文件
public class OkHttpActivity extends AppCompatActivity implements View.OnClickListener {

    public final static String TAG = "OkHttpActivity";
    private GetTextItem getTextItem;
    private TextView tv_http;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_ok_http);
        tv_http = findViewById(R.id.text_okhttp);
        Button btu = findViewById(R.id.btn);
        btu.setOnClickListener(this);
    }
    private void GetRequest() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    // 创建一个OkHttpClient的实例
                    OkHttpClient client = new OkHttpClient();
                    // 如果要发送一条HTTP请求,就需要创建一个Request对象
                    // 可在最终的build()方法之前连缀很多其他方法来丰富这个Request对象
                    Request request = new Request.Builder()
                            .url("https://wanandroid.com/wxarticle/chapters/json")
                            .build();
                    // 调用OkHttpClient的newCall()方法来创建一个Call对象,并调用execute()方法来发送请求并获取服务器的返回数据
                    Response response = client.newCall(request).execute();
                    // 其中Response对象就是服务器返回的数据,将数据转换成字符串
                    String responseData = response.body().string();
                    // 将获取到的字符串传入showResponse()方法中进行UI显示
                    updateUI(responseData);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

    private void updateUI(final String responsese) {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                //这里进行UI操作
                tv_http.setText(responsese);
            }
        });
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.btn:
                GetRequest();
                break;
            default:
                break;
        }
    }
}

这就是全部的流程了,但是特别要注意:不能用xml文件内的onClick,必须中规中矩的设置id,找到控件,设置点击事件这些流程。

然后就是多用一哈,就问题不大了。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pP681aD8-1620478687702)(C:\Users\23737\AppData\Roaming\Typora\typora-user-images\image-20210508101747168.png)]

4.同步和异步传输的区别:

**同步:**发送请求到服务器之后,等数据返回的过程中不能向下执行,只能等数据返回后才能继续执行代码;

异步: 异步传输和同步传输相反,异步传输指的是等数据返回的过程中可以继续执行;一般都在用异步传输。

5.post方式提交字符串

1.继续新建活动,在xml文件下添加一个按钮,用来提交字符串
2.继续创建一个实体类,用来将json封装成一个类
public class CommentItem {
    private String username;
    private String password;
    private String repassword;

    public String getRepassword() {
        return repassword;
    }

    public CommentItem(String username) {
        this.username = username;
    }


    public CommentItem(String username, String password,String repassword) {
        this.username = username;
        this.password = password;
        this.repassword = repassword;
    }

    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;
    }
}
3.最后在.java文件下编写代码(与get方式有区别,注意区分):
public class OkHttpPostActitivty extends AppCompatActivity {
    public final static String TAG = "OkHttpPostActitivty";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_ok_http_post_actitivty);
    }

    public void PostRequest(View view){
        //要有一个浏览器client
        OkHttpClient okHttpClient = new OkHttpClient.Builder()
                .connectTimeout(100000, TimeUnit.MILLISECONDS)
                .build();
        
        //post里面要提交内容,所以在这儿要设置内容
        CommentItem commentItem = new CommentItem("123456","hsk","hsk");
        Gson gson = new Gson();
        String jsonStr = gson.toJson(commentItem);
           //MediaType媒体类型:决定浏览器将以什么形式、什么编码对资源进行解析
        MediaType mediaType = MediaType.parse("application/json");
        final RequestBody requestBody = RequestBody.create(jsonStr,mediaType);
        
        //创建请求内容
        Request request   = new Request.Builder()
                .post(requestBody)
                .url("https://www.wanandroid.com/user/register")
                .build();

        //client去创建请求任务
        Call task = okHttpClient.newCall(request);
        task.enqueue(new Callback() {
            @Override
            public void onFailure(@NotNull Call call, @NotNull IOException e) {
                Log.d(TAG, "onFailure: "+e.toString());
            }

            @Override
            public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
                int code = response.code();
                ResponseBody body = response.body();
                if (body != null) {
                    Log.d(TAG, "onResponse: "+body.string());
                }
            }
        });
    }
}

首先需要注意的是既然是post方式提交,必须要有提交内容。所以在设置请求内容之前就必须先设置内容。Gson解析,然后RequestBody把内容封装起来,最后传入post内的参数里面。

在异步传输的过程中也要注意,onResponse()里面也要用RequestBody来获取内容。通俗的说RequestBody在网络编程这块很多都是用来获取内容。

4.MediaType
类型描述
text/htmlHTML格式
text/plain纯文本格式,空格转换为 “+” 加号,但不对特殊字符编码
text/xmlXML格式
text/x-markdownMarkdown格式
image/gifgif图片格式
image/jpegjpg图片格式
image/pngpng图片格式
application/xhtml+xmlXHTML格式
application/xmlXML数据格式
application/json用来告诉服务端,消息主体是序列化后的JSON字符串
application/pdfpdf格式
application/mswordWord文档格式
application/octet-stream二进制流数据(如常见的文件下载)
application/x-www-form-urlencoded参数为键值对形式,在发送前编码所有字符(默认)。浏览器的原生 <form encType=”” 表单提交类型,如果不设置 enctype 属性,那么最终就会以 application/x-www-form-urlencoded 方式提交数据
multipart/form-data不对字符编码,发送大量二进制数据或包含non-ASCII字符的文本,application/x-www-form-urlencoded是效率低下的(需要用更多字符表示一个non-ASCII字符)。需要设定“ <form enctype=‘multipart/form-data’

6.使用OKhttp上传单个文件

1.继续创一个新活动,添加一个按钮,添加点击事件
2. 实现的代码部分
public class OkHttpPostFileActitivty extends AppCompatActivity {
    public static final String BASE_URL = "http://10.0.2.2:9102";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_ok_http_post_file_actitivty);
    }

    public void OhPostFile(View view){
        //首先要有一个浏览器client
        OkHttpClient okHttpClient = new OkHttpClient.Builder()
                .connectTimeout(100000, TimeUnit.MILLISECONDS)
                .build();

        //因为addFormDataPart()中需要传入一个文件名,所以要在这创建文件
        File file = new File("/storage/emulated/Android/data/files/1.png");

        //因为RequestBody.create需要传入一个MediaType,所以在此创建
        MediaType mediaType = MediaType.parse("/image/png");

        //因为addFormDataPart()中还需要传入一个requestBody,所以要在这创建
            //RequestBody.create()中需要传参的原因:里面存放一些信息参数。例如用的什么编码。如果客户端与服务器端编码不一致,那下载下来可能就有乱码了。这相当于是一个事先说明
        RequestBody fileBidy = RequestBody.create(file,mediaType);

        //post要传进去一个RequestBody,所以在这设置内容
        RequestBody requestBody = new MultipartBody.Builder()
                .addFormDataPart("file",file.getName(),fileBidy)
                .build();

        //创建一个请求内容
        Request request = new Request.Builder()
                .post(requestBody)
                .url(BASE_URL + "/file/upload")
                .build();

        //client创建请求任务
        Call task = okHttpClient.newCall(request);

        //异步请求
        task.enqueue(new Callback() {
            private static final String TAG = "OkHttpPostFileActitivty";

            @Override
            public void onFailure(@NotNull Call call, @NotNull IOException e) {
                Log.d(TAG, "onFailure: "+e.toString());
            }

            @Override
            public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
                int code = response.code();
                if(code == 200){
                    ResponseBody body = response.body();
                    if (body != null) {
                        String string = body.string();
                        Log.d(TAG, "onResponse: "+string);
                    }
                }
            }
        });
    }
}

补充一点重要的东西:

  • RequestBody.create()携带的参数有什么用呢?答:里面存放一些信息参数,例如用的什么编码。如果客户端与服务器端编码不一致,那下载下来可能就有乱码了。这相当于是一个事先说明;
  • RequestBody是干嘛呢? 答:RequestBody的作用其实是将json格式的字符串转换为java对象;
  • https://blog.csdn.net/yihuangol/article/details/105434590?utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7Edefault-5.vipsorttest&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7Edefault-5.vipsorttest

7.使用OKhttp上传多个文件

1.添加一个按钮并且为其添加点击事件
2.编辑代码(和上传单文件基本相同)
public void OhPostFiles(View view){
        //首先要有一个浏览器client
        OkHttpClient okHttpClient = new OkHttpClient.Builder()
                .connectTimeout(100000, TimeUnit.MILLISECONDS)
                .build();

        //因为addFormDataPart()中需要传入一个文件名,所以要在这创建文件
        File fileOne = new File("/storage/emulated/Android/data/files/1.png");
        File fileTwo = new File("/storage/emulated/Android/data/files/2.png");
        File fileThree = new File("/storage/emulated/Android/data/files/3.png");
        File fileFour = new File("/storage/emulated/Android/data/files/4.png");

        //因为RequestBody.create需要传入一个MediaType,所以在此创建
        MediaType mediaType = MediaType.parse("/image/png");

        //因为addFormDataPart()中还需要传入一个requestBody,所以要在这创建
        //RequestBody.create()中需要传参的原因:里面存放一些信息参数。例如用的什么编码。如果客户端与服务器端编码不一致,那下载下来可能就有乱码了。这相当于是一个事先说明
        RequestBody fileOneBidy = RequestBody.create(fileOne,mediaType);
        RequestBody fileTwoBidy = RequestBody.create(fileTwo,mediaType);
        RequestBody fileThreeBidy = RequestBody.create(fileThree,mediaType);
        RequestBody fileFourBidy = RequestBody.create(fileFour,mediaType);

        //post要传进去一个RequestBody,所以在这设置内容
        RequestBody requestBody = new MultipartBody.Builder()
                .addFormDataPart("file",fileOne.getName(),fileOneBidy)
                .addFormDataPart("file",fileTwo.getName(),fileTwoBidy)
                .addFormDataPart("file",fileThree.getName(),fileThreeBidy)
                .addFormDataPart("file",fileFour.getName(),fileFourBidy)
                .build();

        //创建一个请求内容
        Request request = new Request.Builder()
                .post(requestBody)
                .url(BASE_URL + "/file/upload")
                .build();

        //client创建请求任务
        Call task = okHttpClient.newCall(request);

        //异步请求
        task.enqueue(new Callback() {
            private static final String TAG = "OkHttpPostFileActitivty";

            @Override
            public void onFailure(@NotNull Call call, @NotNull IOException e) {
                Log.d(TAG, "onFailure: "+e.toString());
            }

            @Override
            public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
                int code = response.code();
                if(code == 200){
                    ResponseBody body = response.body();
                    if (body != null) {
                        String string = body.string();
                        Log.d(TAG, "onResponse: "+string);
                    }
                }
            }
        });
    }

单文件只需要创建一个文件流,多文件多创建几个,传几个就创几个;然后用到文件流的地方都继续创建就欧了。

8.OKhttp下载文件

1.创建一个新的活动,添加两个按钮,分别用来实现同步请求和异步请求
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".Activity.OkHttpPostFileActitivty"
    android:orientation="vertical">

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:onClick="OhDownFilesSynchronous"
        android:text="okhttp 同步下载文件"
        tools:ignore="OnClick" />
    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:onClick="OhDownFilesAsynchronous"
        android:text="okhttp 异步下载文件"
        tools:ignore="OnClick" />

</LinearLayout>
2.okhttp使用同步方式下载文件
public class OkhttpDownFileActivity extends AppCompatActivity {

    public static final String TAG = "OkhttpDownFileActivity";
    public static final String BASE_URL = "http://10.0.2.2:9102";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_okhttp_down_file);
    }


    //同步下载文件
    public void OhDownFilesSynchronous(View view) {
        //创建一个浏览器
        OkHttpClient okHttpClient = new OkHttpClient.Builder()
                .connectTimeout(10000, TimeUnit.MILLISECONDS)
                .build();
        //创建一个请求
        Request request = new Request.Builder()
                .get()
                .url(BASE_URL + "/download/5")
                .build();
        //client去创建请求任务
        final Call task = okHttpClient.newCall(request);
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    //同步请求开始了
                    Response execute = task.execute();
                    //拿到一个请求头
                    Headers headers = execute.headers();
                    for (int i = 0; i < headers.size(); i++) {
                        //获取请求头里面的name和value
                        String name = headers.name(i);
                        String value = headers.value(i);
                        Log.d(TAG, name + "run: " + value);
                    }
                    InputStream inputStream = execute.body().byteStream();
                    DownFile(inputStream, headers);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }
    //下载文件的关键代码封装成一个方法
    private void DownFile(final InputStream inputStream, final Headers headers) throws IOException {
        String contentType = headers.get("Content-Type");
        String fileName = contentType.replace("attachment;filename=", "");
        File outFile = new File(OkhttpDownFileActivity.this.getExternalFilesDir(Environment.DIRECTORY_PICTURES) + File.separator + fileName);
        if(!outFile.getParentFile().exists()){
            outFile.mkdirs();
        }
        if(!outFile.exists()){
            outFile.createNewFile();
        }
        //创建一个文件输出流
        FileOutputStream fos = new FileOutputStream(outFile);
            byte[] buffer = new byte[1024];
            int len;
            while((len=inputStream.read(buffer,0,buffer.length))!=-1){
                fos.write(buffer,0,len);
            fos.flush();
        }
    }
}
3.okhttp使用异步方式来进行文件的下载
public class OkhttpDownFileActivity extends AppCompatActivity {

    public static final String TAG = "OkhttpDownFileActivity";
    public static final String BASE_URL = "http://10.0.2.2:9102";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_okhttp_down_file);
    }
     //异步下载文件
    public void OhDownFilesAsynchronous(View view) {
        //创建一个浏览器
        OkHttpClient okHttpClient = new OkHttpClient.Builder()
                .connectTimeout(10000, TimeUnit.MILLISECONDS)
                .build();
        //创建一个请求
        Request request = new Request.Builder()
                .get()
                .url(BASE_URL + "/download/5")
                .build();
        //client去创建请求任务
         Call task = okHttpClient.newCall(request);
         //继续异步传输
        task.enqueue(new Callback() {
            @Override
            public void onFailure(@NotNull Call call, @NotNull IOException e) {
                e.printStackTrace();
            }

            @Override
            public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
                int code = response.code();
                if (code == HttpURLConnection.HTTP_OK){
                    DownFile(response.body().byteStream(),response.headers());
                }
            }
        });
    }

    //下载文件的关键代码封装成一个方法
    private void DownFile(final InputStream inputStream, final Headers headers) throws IOException {
        String contentType = headers.get("Content-Type");
        String fileName = contentType.replace("attachment;filename=", "");
        File outFile = new File(OkhttpDownFileActivity.this.getExternalFilesDir(Environment.DIRECTORY_PICTURES) + File.separator + fileName);
        if(!outFile.getParentFile().exists()){
            outFile.mkdirs();
        }
        if(!outFile.exists()){
            outFile.createNewFile();
        }
        //创建一个文件输出流
        FileOutputStream fos = new FileOutputStream(outFile);
            byte[] buffer = new byte[1024];
            int len;
            while((len=inputStream.read(buffer,0,buffer.length))!=-1){
                fos.write(buffer,0,len);
            fos.flush();
        }
    }
}

**把下载文件的核心代码封装成一个方法,自动封装过程:**右键->Refactor->Extract Method

封装成的方法里边其实主要就是 文件的写入和读取

!!!OKhttp就先到这吧,学的很浅,以后用到再深学

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值