OkHttp 系列文章目录

【OkHttp】OkHttp 简介 ( OkHttp 框架特性 | Http 版本简介 )

【OkHttp】Android 项目导入 OkHttp ( 配置依赖 | 配置 networkSecurityConfig | 配置 ViewBinding | 代码示例 )

【OkHttp】OkHttp Get 和 Post 请求 ( 同步 Get 请求 | 异步 Get 请求 | 同步 Post 请求 | 异步 Post 请求 )

【OkHttp】OkHttp 上传图片 ( 获取 SD 卡动态权限 | 跳转到相册界面选择图片 | 使用 OkHttp 上传图片文件 )


文章目录

  • OkHttp 系列文章目录
  • 前言
  • 一、获取 SD 卡动态权限
  • 二、跳转到相册界面
  • 三、选择完相册图片后回到本界面
  • 四、使用 OkHttp 上传图片文件 ( 核心步骤 )
  • 五、完整代码示例
  • 六、博客资源

前言

在上一篇博客 【OkHttp】OkHttp Get 和 Post 请求 ( 同步 Get 请求 | 异步 Get 请求 | 同步 Post 请求 | 异步 Post 请求 ) 中介绍了 OkHttp 的 同步 / 异步 的 Get / Post 请求 , 本篇博客开始讲解文件的上传 ;


一、获取 SD 卡动态权限


在清单文件中 , 注册如下权限 ;

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

在 Activity 中 , 动态申请权限 , 这里使用到了一个动态权限库 ;

此处也可以使用原生代码自己开发动态权限申请 【Android 应用开发】动态权限管理示例 ( 使用原生代码实现 | 申请权限 | 判定权限申请结果 | 判定 “ 不再询问 “ 情况 ) ,

也可以使用 Google 官方的 EasyPermission 权限框架 【Android 应用开发】Google 官方 EasyPermissions 权限申请库 ( 完整代码示例 | 申请权限 | 申请权限原理对话框 | 引导用户手动设置权限对话框 ) ;

// 申请权限
AndPermission.with(this)
.runtime()
.permission(
// 申请 SD 卡权限
Permission.WRITE_EXTERNAL_STORAGE,
Permission.READ_EXTERNAL_STORAGE
).onGranted(new Action<List<String>>() {
@Override
public void onAction(List<String> data) {
// 所有权限都通过
}
}).onDenied(new Action<List<String>>() {
@Override
public void onAction(List<String> data) {
// 存在至少 1 个权限被拒绝
}
}).start();

二、跳转到相册界面


使用下面的 Intent 设置 , 跳转到相册图片选择界面 ;

// 跳转到相册界面
Intent intent = new Intent(
Intent.ACTION_PICK,
android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(intent, REQUEST_CODE);

三、选择完相册图片后回到本界面


① 首先 , 判定是否获取成功 , 如果图片获取成功 , 再向下继续执行 ;

//获取图片路径
if (requestCode == REQUEST_CODE
&& resultCode == Activity.RESULT_OK
&& data != null) {

② 其次 , 获取图像的 Uri , 这是查找图片的唯一依据 ;

// 获取图像 Uri
Uri imageUri = data.getData();

③ 再次 , 查询数据库中 , Uri 对应图片的文件路径 ; 文件路径所在的字段是 MediaStore.Images.Media.DATA 字段 , 列明为 _data ;

// 要查询的列字段名称
String[] filePathColumns = {MediaStore.Images.Media.DATA};

// 到数据库中查询 , 查询 _data 列字段信息
Cursor cursor = getContentResolver().query(
imageUri,
filePathColumns,
null,
null,
null);

cursor.moveToFirst();
// 获取 _data 列所在的列索引
int columnIndex = cursor.getColumnIndex(filePathColumns[0]);
// 获取图片的存储路径
String filePath = cursor.getString(columnIndex);


// 获取数据完毕后, 关闭游标
cursor.close();

④ 最后 , 使用 OkHttp 上传获取的图片对应的文件路径 ;

完整代码示例 :

/**
* 在相册中选择图片返回
* @param requestCode
* @param resultCode
* @param data
*/
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
//获取图片路径
if (requestCode == REQUEST_CODE
&& resultCode == Activity.RESULT_OK
&& data != null) {
// 获取图像 Uri
Uri imageUri = data.getData();
// 要查询的列字段名称
String[] filePathColumns = {MediaStore.Images.Media.DATA};

// 到数据库中查询 , 查询 _data 列字段信息
Cursor cursor = getContentResolver().query(
imageUri,
filePathColumns,
null,
null,
null);
cursor.moveToFirst();
// 获取 _data 列所在的列索引
int columnIndex = cursor.getColumnIndex(filePathColumns[0]);
// 获取图片的存储路径
String filePath = cursor.getString(columnIndex);

// 使用 OkHttp 上传图片
upload(filePath);

// 获取数据完毕后, 关闭游标
cursor.close();
}
}

四、使用 OkHttp 上传图片文件 ( 核心步骤 )


① 首先 , 构造请求体 ;

File file = new File(filePath);

// 请求体
RequestBody body = new MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart(
"file",
file.getName(),
MultipartBody.create(MediaType.parse("multipart/form-data"), file)
).build();

② 然后 , 创建 Post 请求 ;

// Post 请求
Request request = new Request.Builder()
.url("https://www.baidu.com")
.post(body)
.build();

③ 最后 , 执行异步 Post 请求 , 上传图片 ;

// 执行异步请求
mOkHttpClient.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {

}

@Override
public void onResponse(Call call, Response response) throws IOException {
String result = response.body().string();
// 上传完毕
}
});

​完整代码示例 :​

/**
* 使用 OkHttp 上传图片
* @param filePath
*/
private void upload(String filePath){
File file = new File(filePath);

// 请求体
RequestBody body = new MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart(
"file",
file.getName(),
MultipartBody.create(MediaType.parse("multipart/form-data"), file)
).build();

// Post 请求
Request request = new Request.Builder()
.url("https://www.baidu.com")
.post(body)
.build();

// 执行异步请求
mOkHttpClient.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {

}

@Override
public void onResponse(Call call, Response response) throws IOException {
String result = response.body().string();
// 上传完毕
}
});
}

五、完整代码示例


package com.example.okhttp;

import androidx.appcompat.app.AppCompatActivity;

import android.Manifest;
import android.app.Activity;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.util.Log;
import android.view.View;

import com.example.okhttp.databinding.ActivityMainBinding;
import com.yanzhenjie.permission.Action;
import com.yanzhenjie.permission.AndPermission;
import com.yanzhenjie.permission.runtime.Permission;

import java.io.File;
import java.io.IOException;
import java.util.List;

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;
import pub.devrel.easypermissions.EasyPermissions;

public class MainActivity extends AppCompatActivity {

private static final String TAG = "MainActivity";

/**
* ViewBinding 类
* activity_main 布局映射出来的类
* 该类主要作用是封装组件的获取
*/
ActivityMainBinding binding;

/**
* OkHttp 客户端
* 注意 : 该类型对象较大, 尽量在应用中创建较少的该类型对象
* 推荐使用单例
*/
OkHttpClient mOkHttpClient;

/**
* Activity 跨页访问的面请求码
*/
public static final int REQUEST_CODE = 1;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ActivityMainBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());

EasyPermissions.requestPermissions(
this,
"权限申请原理对话框 : 描述申请权限的原理",
100,

// 下面是要申请的权限 可变参数列表
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_EXTERNAL_STORAGE
);

mOkHttpClient = new OkHttpClient();

binding.button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//httpSynchronousGet();
//httpAsynchronousGet();
//httpSynchronousPost();
//httpAsynchronousPost();
httpUploadPhoto();
}
});
}

/**
* OkHttp 同步 Get 请求
*/
private void httpSynchronousGet() {
// Request 中封装了请求相关信息
Request request = new Request.Builder()
.url("https://www.baidu.com") // 设置请求地址
.get() // 使用 Get 方法
.build();

// 同步 Get 请求
new Thread(new Runnable() {
@Override
public void run() {
Response response = null;
try {
response = mOkHttpClient.newCall(request).execute();
} catch (IOException e) {
e.printStackTrace();
}

String result = null;
try {
result = response.body().string();
} catch (IOException e) {
e.printStackTrace();
}
Log.i(TAG, "result : " + result);
}
}).start();
}

/**
* OkHttp 异步 Get 请求
*/
private void httpAsynchronousGet() {
// Request 中封装了请求相关信息
Request request = new Request.Builder()
.url("https://www.baidu.com") // 设置请求地址
.get() // 使用 Get 方法
.build();

// 创建异步回调
Callback callback = new Callback(){

@Override
public void onFailure(Call call, IOException e) {
// 请求失败的情况
}

@Override
public void onResponse(Call call, Response response) throws IOException {
// 请求成功 , 获取
String result = response.body().string();
Log.i(TAG, "result : " + result);
runOnUiThread(new Runnable() {
@Override
public void run() {
// 主线程中执行相关代码
}
});
}
};

// 异步 Get 请求
mOkHttpClient.newCall(request).enqueue(callback);
}

/**
* OkHttp 同步 Post 请求
*/
private void httpSynchronousPost() {
// 创建 Post 表单 , 主要用于设置 Post 请求键值对
FormBody formBody = new FormBody.Builder()
.add("Key", "Value")
.build();

// Request 中封装了请求相关信息
Request request = new Request.Builder()
.url("https://www.baidu.com") // 设置请求地址
.post(formBody) // 使用 Post 方法
.build();

// 同步 Get 请求
new Thread(new Runnable() {
@Override
public void run() {
Response response = null;
try {
response = mOkHttpClient.newCall(request).execute();
} catch (IOException e) {
e.printStackTrace();
}

String result = null;
try {
result = response.body().string();
} catch (IOException e) {
e.printStackTrace();
}
Log.i(TAG, "result : " + result);
}
}).start();
}

/**
* OkHttp 异步 Post 请求
*/
private void httpAsynchronousPost() {
// 创建 Post 表单 , 主要用于设置 Post 请求键值对
FormBody formBody = new FormBody.Builder()
.add("Key", "Value")
.build();

// Request 中封装了请求相关信息
Request request = new Request.Builder()
.url("https://www.baidu.com") // 设置请求地址
.post(formBody) // 使用 Post 方法
.build();

// 创建异步回调
Callback callback = new Callback(){

@Override
public void onFailure(Call call, IOException e) {
// 请求失败的情况
}

@Override
public void onResponse(Call call, Response response) throws IOException {
// 请求成功 , 获取
String result = response.body().string();
Log.i(TAG, "result : " + result);
runOnUiThread(new Runnable() {
@Override
public void run() {
// 主线程中执行相关代码
}
});
}
};

// 异步 Get 请求
mOkHttpClient.newCall(request).enqueue(callback);
}

/**
* 上传图片
*/
private void httpUploadPhoto() {
// 申请权限
AndPermission.with(this)
.runtime()
.permission(
// 申请 SD 卡权限
Permission.WRITE_EXTERNAL_STORAGE,
Permission.READ_EXTERNAL_STORAGE
).onGranted(new Action<List<String>>() {
@Override
public void onAction(List<String> data) {
// 所有权限都通过
// 跳转到相册界面
Intent intent = new Intent(
Intent.ACTION_PICK,
android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(intent, REQUEST_CODE);
}
}).onDenied(new Action<List<String>>() {
@Override
public void onAction(List<String> data) {
// 存在至少 1 个权限被拒绝
}
}).start();
}

/**
* 在相册中选择图片返回
* @param requestCode
* @param resultCode
* @param data
*/
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
//获取图片路径
if (requestCode == REQUEST_CODE
&& resultCode == Activity.RESULT_OK
&& data != null) {
// 获取图像 Uri
Uri imageUri = data.getData();
// 要查询的列字段名称
String[] filePathColumns = {MediaStore.Images.Media.DATA};

// 到数据库中查询 , 查询 _data 列字段信息
Cursor cursor = getContentResolver().query(
imageUri,
filePathColumns,
null,
null,
null);
cursor.moveToFirst();
// 获取 _data 列所在的列索引
int columnIndex = cursor.getColumnIndex(filePathColumns[0]);
// 获取图片的存储路径
String filePath = cursor.getString(columnIndex);

// 使用 OkHttp 上传图片
upload(filePath);

// 获取数据完毕后, 关闭游标
cursor.close();
}
}

/**
* 使用 OkHttp 上传图片
* @param filePath
*/
private void upload(String filePath){
File file = new File(filePath);

// 请求体
RequestBody body = new MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart(
"file",
file.getName(),
MultipartBody.create(MediaType.parse("multipart/form-data"), file)
).build();

// Post 请求
Request request = new Request.Builder()
.url("https://www.baidu.com")
.post(body)
.build();

// 执行异步请求
mOkHttpClient.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {

}

@Override
public void onResponse(Call call, Response response) throws IOException {
String result = response.body().string();
// 上传完毕
}
});
}


}

六、博客资源


​GitHub :​ https://github.com/han1202012/OkHttp