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

2023-03-29 14:21:15 浏览数 (2)

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 卡动态权限


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

代码语言:javascript复制
    <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 权限申请库 ( 完整代码示例 | 申请权限 | 申请权限原理对话框 | 引导用户手动设置权限对话框 ) ;

代码语言:javascript复制
        // 申请权限
        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 设置 , 跳转到相册图片选择界面 ;

代码语言:javascript复制
// 跳转到相册界面
Intent intent = new Intent(
        Intent.ACTION_PICK,
        android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(intent, REQUEST_CODE);

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


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

代码语言:javascript复制
        //获取图片路径
        if (requestCode == REQUEST_CODE
                && resultCode == Activity.RESULT_OK
                && data != null) {

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

代码语言:javascript复制
// 获取图像 Uri
Uri imageUri = data.getData();

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

代码语言:javascript复制
// 要查询的列字段名称
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 上传获取的图片对应的文件路径 ;

完整代码示例 :

代码语言:javascript复制
    /**
     * 在相册中选择图片返回
     * @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 上传图片文件 ( 核心步骤 )


① 首先 , 构造请求体 ;

代码语言:javascript复制
        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 请求 ;

代码语言:javascript复制
        // Post 请求
        Request request = new Request.Builder()
                .url("https://www.baidu.com")
                .post(body)
                .build();

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

代码语言:javascript复制
        // 执行异步请求
        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();
                // 上传完毕
            }
        });

完整代码示例 :

代码语言:javascript复制
    /**
     * 使用 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();
                // 上传完毕
            }
        });
    }

五、完整代码示例


代码语言:javascript复制
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

0 人点赞