okhttp的使用

android网络框架之OKhttp一个处理网络请求的开源项目,是安卓端最火热的轻量级框架,适用于 JVM、Android 和 GraalVM 的细致 HTTP 客户端。

GitHub开源地址:https://github.com/square/okhttp

一、引用第三方包okhttp

1、在模块的build.gradle文件中加入:

dependencies {
          implementation 'com.squareup.okhttp3:okhttp:4.12.0'   
}

2、点击File->Sync Project with Gradle Files

image.png

3、在AndroidManifest.xml文件中加入:

<uses-permission android:name="android.permission.INTERNET" />

作用:使项目可以连接网络,默认是不允许访问网络的

在节点application中加入属性android:usesCleartextTraffic="true",以允许发送http请求,默认只允许发送https请求。

结果如图所示:

image.png

二、okhttp的使用

1、发送get请求

get请求分同步和异步两种方式。

(1)发送同步get请求

package com.example.myapplication;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import java.io.IOException;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
public class MainActivity extends AppCompatActivity  {
    private TextView tv1;
    private Handler handler=new Handler(Looper.getMainLooper());
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tv1 = findViewById(R.id.tv1);
        findViewById(R.id.btn1).setOnClickListener(v->{
            new Thread(){
                @Override
                public void run() {
                    super.run();
                    OkHttpClient client=new OkHttpClient();
                    Request request= new Request.Builder().url("https://www.baidu.com").build(); //或new Request.Builder().url("https://www.baidu.com").get().build();
                    try {
                        Response response=client.newCall(request).execute();//execute()为同步请求
                        String data=response.body().string();
                        //陌生线程不能直接访问UI线程的,所以要使用handler.post()
                        handler.post(new Runnable() {
                            @Override
                            public void run() {
                                tv1.setText(data);
                            }
                        });
                    } catch (IOException e) {
                        throw new RuntimeException(e);
                    }
                }
            }.start();
        });
    }
}

用lambda表达式:

new Thread(()->{
     OkHttpClient client=new OkHttpClient();
     Request request=new Request.Builder().url("https://www.baidu.com").build();
     try {
          Response response=client.newCall(request).execute();
          String data=response.body().string();
          handler.post(()->{
               tv1.setText(data);
          });
      } catch (IOException e) {
          throw new RuntimeException(e);
      }
}).start();

(2)发送异步get请求

findViewById(R.id.btn1).setOnClickListener(v -> {
    OkHttpClient client = new OkHttpClient();
    Request request = new Request.Builder().url("https://www.baidu.com").build(); //或new Request.Builder().url("https://www.baidu.com").get().build();
    client.newCall(request).enqueue(new Callback() {
        @Override
        public void onFailure(@NonNull Call call, @NonNull IOException e) {
        }
        @Override
        public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
            String data = response.body().string();
            handler.post(()->{
                tv1.setText(data);
            });
        }
    });
});

同步用execute(),须手动创建线程;异步用enqueue(),会自动创建线程。

response.body().string()只能调用一次,在第一次时有返回值,第二次再调用时将会返回null。

response.body().string()要放在子线程中。

(3)传递参数

①以查询字符串形式传递参数,如http://124.93.196.45:10091/Neusoft/community/api/adv/list?title=开屏广告2&status=1

②构建HttpUrl.Builder对象

HttpUrl.Builder url=HttpUrl.parse("http://124.93.196.45:10091/Neusoft/community/api/adv/list").newBuilder();
url.addQueryParameter("title","开屏广告2");
url.addQueryParameter("status", "1");

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

2、发送post请求

post请求也分同步和异步两种方式,同步与异步的区别和get方法类似,这里只讲发送post异步请求的使用方法。 

(1)post发送普通表单数据

String url = "https://example.com.cn/logincheck.php";
FormBody body=new FormBody.Builder()    //FormBody继承自RequestBody
        .add("UNAME","")
        .add("PASSWORD", "")
        .add("CAPTCHA", "")
        .build();
OkHttpClient client=new OkHttpClient();            
Request request=new Request.Builder().url(url).post(body).build();
client.newCall(request).enqueue(new Callback() {
    @Override
    public void onFailure(@NonNull Call call, @NonNull IOException e) {
    }
    @Override
    public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
        if(response.isSuccessful()) {
            String data=response.body().string();
            handler.post(()->{
                tv1.setText(data);
            });
        }
    }
});

内容类型自动为:application/x-www-form-urlencoded。

(2)post发送含文件的表单数据

String url = "http://124.93.196.45:10091/Neusoft/times-model" + "/appUser/updatePersonaInfo";
File file = new File("/sdcard/ava.png");
RequestBody filebody = RequestBody.create(file, MediaType.parse("images/png"));
MultipartBody body = new MultipartBody.Builder() //MultipartBody继承自RequestBody
        .setType(MultipartBody.FORM)
        .addFormDataPart("name", "abcd")
        .addFormDataPart("sex", "2")
        .addFormDataPart("email", "2632422@qq.com")
        .addFormDataPart("avatarfile", file.getName(), filebody)
        .build();

Request request = new Request.Builder().url(url).post(body).header("Authorization", token).build();
client.newCall(request).enqueue(new Callback() {
    @Override
    public void onFailure(@NonNull Call call, @NonNull IOException e) {
        ……
    }
    @Override
    public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
        if (response.isSuccessful()) {
            String data = response.body().string();
            ……           
        }
    }
});

内容类型自动为:multipart/form-data。

默认情况下不允许访问存储卡,若要允许访问存储卡,则需要以下两步:

①在AndroidManifest.xml文件中加入

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
结果如图所示:
image.png
在调试的设备或模拟器中,app访问存储的权限是关闭的,解决方法是: 在Settings->Apps->找到并点击你的应用->Permissions->File and Media,如下图
image.png
或者在代码中申请权限,具体如下:
if(ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE)!= PackageManager.PERMISSION_GRANTED){  //判断是否有相关权限
    ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},1); //请求相关权限
}else{
    ……
}
(3)post单独上传文件

String url = "http://example.com.cn/upload";
File file = new File("/sdcard/ava.png");
RequestBody body = RequestBody.create(file, MediaType.parse("application/octet-stream"));
Request request = new Request.Builder().url(url).post(body).build();
client.newCall(request).enqueue(new Callback() {
    @Override
    public void onFailure(@NonNull Call call, @NonNull IOException e) {
        ……
    }
    @Override
    public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
        if (response.isSuccessful()) {
            String data = response.body().string();
            ……           
        }
    }
});
(4)post发送json数据

String url = "http://124.93.196.45:10091/Neusoft/community" + "/api/login";
String json="{\"username\":\"\",\"password\":\"\"}"; //json字符串
RequestBody body=RequestBody.create(json,MediaType.parse("application/json;charset=utf-8"));

OkHttpClient client=new OkHttpClient();
Request request=new Request.Builder().url(url).post(body).build();
client.newCall(request).enqueue(new Callback() {
    @Override
    public void onFailure(@NonNull Call call, @NonNull IOException e) {
    }
    @Override
    public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
        if(response.isSuccessful()) {
            String data=response.body().string();
            handler.post(()->{
                tv1.setText(data);
            });
        }
    }
});

(5)post发送无参数请求

String url = "http://example.com.cn/post";
OkHttpClient client=new OkHttpClient();
Request request=new Request.Builder().url(url).post(RequestBody.create("",null)).build();
client.newCall(request).enqueue(new Callback() {
    @Override
    public void onFailure(@NonNull Call call, @NonNull IOException e) {
        ……
    }
    @Override
    public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
        if(response.isSuccessful()) {
            String data=response.body().string();
            ……
        }
    }
});

3、发送请求头信息


4、处理返回的信息



可以使用第三方包gson(gson的github开源地址为:https://github.com/google/gson)在json字符串与对象之间进行转换。

要使用gson,则在模块的build.gradle文件中加入:

dependencies {
  implementation 'com.google.code.gson:gson:2.11.0'
}

新建类:

public class User {
    private  String username;
    private String password;
    public User(String name,String pass){
        this.username=name;
        this.password=pass;
    }
    public String getUsername() { return username; }
    public String getPassword() { return password;}
}

对象转换为json字符串:

User user=new User("", "");
String json=new Gson().toJson(user);

json字符串转换为对象:

String json="{\"username\":\"\",\"password\":\"\"}";
User user=new Gson().fromJson(json,User.class);