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/html | HTML格式 |
text/plain | 纯文本格式,空格转换为 “+” 加号,但不对特殊字符编码 |
text/xml | XML格式 |
text/x-markdown | Markdown格式 |
image/gif | gif图片格式 |
image/jpeg | jpg图片格式 |
image/png | png图片格式 |
application/xhtml+xml | XHTML格式 |
application/xml | XML数据格式 |
application/json | 用来告诉服务端,消息主体是序列化后的JSON字符串 |
application/pdf | pdf格式 |
application/msword | Word文档格式 |
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就先到这吧,学的很浅,以后用到再深学