Android App开发网络通信中使用okhttp下载和上传图片、文件讲解及实战(超详细实现用户注册信息上传 附源码)

简介: Android App开发网络通信中使用okhttp下载和上传图片、文件讲解及实战(超详细实现用户注册信息上传 附源码)

需要源码请点赞关注收藏后评论区留言并且私信~~~

一、使用okhttp下载图片

okhttp不但简化了HTTP接口的调用过程,连下载文件都变得简单了,对于一般的文件下载,按照常规的GET方式调用流程,只要重写回调方法onResponse,在该方法中通过应答对象的body方法即可获得应答的数据包对象,调用数据包对象的string方法即可得到文本形式的字符串,下面以下载网络图片为例,位图工具BitmapFactory刚好提供了decodeStream方法,允许直接从输入流中解码获取位图对象 效果如下

点击下载图片按钮后即可自动实现下载网络图片

二、利用okhttp下载文件

当然,网络文件不止是图片,还有各种各样的文件,这些文件没有专门的解码工具,只能从输入流老老实实的读取字节数据,不过读取字节数据有个好处,就是能够根据已经读写的数据长度计算下载进度,特别在下载大文件的时候,实时展示当前的下载进度非常有用

效果如下 演示视频已上传至个人主页 可自行观看

由下图可见下载进度加载到了百分之一百

 

代码如下

Java类

package com.example.network;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.os.Environment;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import 
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
 = "https://ptgl.fujian.gov.cn:8088/masvod/public/2021/03/19/20210319_178498bcae9_r38.mp4";
    private TextView tv_result; // 声明一个文本视图对象
    private TextView tv_progress; // 声明一个文本视图对象
    private ImageView iv_result; // 声明一个图像视图对象
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_okhttp_download);
        tv_result = findViewById(R.id.tv_result);
        tv_progress = findViewById(R.id.tv_progress);
        iv_result = findViewById(R.id.iv_result);
        findViewById(R.id.btn_download_image).setOnClickListener(v -> downloadImage());
        findViewById(R.id.btn_download_file).setOnClickListener(v -> downloadFile());
    }
    // 下载网络图片
    private void downloadImage() {
        tv_progress.setVisibility(View.GONE);
        iv_result.setVisibility(View.VISIBLE);
        OkHttpClient client = new OkHttpClient(); // 创建一个okhttp客户端对象
        // 创建一个GET方式的请求结构
        Request request = new Request.Builder().url(URL_IMAGE).build();
        Call call = client.newCall(request); // 根据请求结构创建调用对象
        // 加入HTTP请求队列。异步调用,并设置接口应答的回调方法
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) { // 请求失败
                // 回到主线程操纵界面
                runOnUiThread(() -> tv_result.setText("下载网络图片报错:"+e.getMessage()));
            }
            @Override
            public void onResponse(Call call, final Response response) { // 请求成功
                InputStream is = response.body().byteStream();
                // 从返回的输入流中解码获得位图数据
                Bitmap bitmap = BitmapFactory.decodeStream(is);
                String mediaType = response.body().contentType().toString();
                long length = response.body().contentLength();
                String desc = String.format("文件类型为%s,文件大小为%d", mediaType, length);
                // 回到主线程操纵界面
                runOnUiThread(() -> {
                    tv_result.setText("下载网络图片返回:"+desc);
                    iv_result.setImageBitmap(bitmap);
                });
            }
        });
    }
    // 下载网络文件
    private void downloadFile() {
        tv_progress.setVisibility(View.VISIBLE);
        iv_result.setVisibility(View.GONE);
        OkHttpClient client = new OkHttpClient(); // 创建一个okhttp客户端对象
        // 创建一个GET方式的请求结构
        Request request = new Request.Builder().url(URL_APK).build();
        Call call = client.newCall(request); // 根据请求结构创建调用对象
        // 加入HTTP请求队列。异步调用,并设置接口应答的回调方法
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) { // 请求失败
                // 回到主线程操纵界面
                runOnUiThread(() -> tv_result.setText("下载网络文件报错:"+e.getMessage()));
            }
            @Override
            public void onResponse(Call call, final Response response) { // 请求成功
                String mediaType = response.body().contentType().toString();
                long length = response.body().contentLength();
                String desc = String.format("文件类型为%s,文件大小为%d", mediaType, length);
                // 回到主线程操纵界面
                runOnUiThread(() -> tv_result.setText("下载网络文件返回:"+desc));
                String path = String.format("%s/%s.apk",
                        getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS).toString(),
                        DateUtil.getNowDateTime());
                // 下面从返回的输入流中读取字节数据并保存为本地文件
                try (InputStream is = response.body().byteStream();
                     FileOutputStream fos = new FileOutputStream(path)) {
                    byte[] buf = new byte[100 * 1024];
                    int sum=0, len=0;
                    while ((len = is.read(buf)) != -1) {
                        fos.write(buf, 0, len);
                        sum += len;
                        int progress = (int) (sum * 1.0f / length * 100);
                        String detail = String.format("文件保存在%s。已下载%d%%", path, progress);
                        // 回到主线程操纵界面
                        runOnUiThread(() -> tv_progress.setText(detail));
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }
}

XML文件

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <Button
            android:id="@+id/btn_download_image"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="下载图片"
            android:textColor="@color/black"
            android:textSize="17sp" />
        <Button
            android:id="@+id/btn_download_file"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="下载文件"
            android:textColor="@color/black"
            android:textSize="17sp" />
    </LinearLayout>
    <TextView
        android:id="@+id/tv_result"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:paddingLeft="5dp"
        android:paddingRight="5dp"
        android:textColor="@color/black"
        android:textSize="17sp" />
    <TextView
        android:id="@+id/tv_progress"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:paddingLeft="5dp"
        android:paddingRight="5dp"
        android:textColor="@color/black"
        android:textSize="17sp" />
    <ImageView
        android:id="@+id/iv_result"
        android:layout_width="match_parent"
        android:layout_height="250dp" />
</LinearLayout>

三、利用okhttp上传文件

okhttp不仅让下载文件变得简单,还让上传文件变得更加灵活易用,比如修改个人资料,头像的时候常常带着文字说明,对于这种组合上传的业务场景,HttpURLConnection编码十分困难,用okhttp就十分简单,它引入分段结构MultipartBody及其建造器,分别适用于文本格式与文件格式的数据

下面举带头像进行用户注册的例子,既要把用户名和密码送给服务端,还要把头像图片传给服务器端

可以自定义用户信息

代码如下

Java类

package com.example.network;
import android.content.Intent;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.text.TextUtils;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import com.example.network.constant.NetConst;
import com.example.network.util.BitmapUtil;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
public class OkhttpUploadActivity extends AppCompatActivity {
    private final static String TAG = "OkhttpUploadActivity";
    public final static String URL_REGISTER = NetConst.HTTP_PREFIX + "register";
    private EditText et_username; // 声明一个编辑框对象
    private EditText et_password; // 声明一个编辑框对象
    private TextView tv_result; // 声明一个文本视图对象
    private ImageView iv_face; // 声明一个图像视图对象
    private int CHOOSE_CODE = 3; // 只在相册挑选图片的请求码
    private List<String> mPathList = new ArrayList<>(); // 头像文件的路径列表
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_okhttp_upload);
        et_username = findViewById(R.id.et_username);
        et_password = findViewById(R.id.et_password);
        iv_face = findViewById(R.id.iv_face);
        tv_result = findViewById(R.id.tv_result);
        iv_face.setOnClickListener(v -> {
            // 创建一个内容获取动作的意图(准备跳到系统相册)
            Intent albumIntent = new Intent(Intent.ACTION_GET_CONTENT);
            albumIntent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, false); // 是否允许多选
            albumIntent.setType("image/*"); // 类型为图像
            startActivityForResult(albumIntent, CHOOSE_CODE); // 打开系统相册
        });
        findViewById(R.id.btn_register).setOnClickListener(v -> uploadFile());
    }
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
        super.onActivityResult(requestCode, resultCode, intent);
        if (resultCode == RESULT_OK && requestCode == CHOOSE_CODE) { // 从相册返回
            mPathList.clear();
            if (intent.getData() != null) { // 从相册选择一张照片
                // 把指定Uri的图片复制一份到内部存储空间,并返回存储路径
                String imagePath = saveImage(intent.getData());
                mPathList.add(imagePath);
            }
        }
    }
    // 把指定Uri的图片复制一份到内部存储空间,并返回存储路径
    private String saveImage(Uri uri) {
        String uriStr = uri.toString();
        String imageName = uriStr.substring(uriStr.lastIndexOf("/")+1);
        String imagePath = String.format("%s/%s.jpg", 
                getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS).toString(), imageName);
        // 获得自动缩小后的位图对象
        Bitmap bitmap = BitmapUtil.getAutoZoomImage(this, uri);
        // 把位图数据保存到指定路径的图片文件
        BitmapUtil.saveImage(imagePath, bitmap);
        iv_face.setImageBitmap(bitmap);
        return imagePath;
    }
    // 执行文件上传动作
    private void uploadFile() {
        if (mPathList.size() <= 0) {
            Toast.makeText(this, "请选择待上传的用户头像", Toast.LENGTH_SHORT).show();
            return;
        }
        // 创建分段内容的建造器对象
        MultipartBody.Builder builder = new MultipartBody.Builder();
        String username = et_username.getText().toString();
        String password = et_password.getText().toString();
        if (!TextUtils.isEmpty(username)) {
            // 往建造器对象添加().string();
                // 回到主线程操纵界面
                runOnUiThread(() -> tv_result.setText("调用注册接口返回:\n"+resp));
            }
        });
    }
}

XML文件

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="5dp"
    android:orientation="vertical">
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="40dp"
        android:orientation="horizontal">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:gravity="center"
            android:text="用户名:"
            android:textColor="@color/black"
            android:textSize="17sp" />
        <EditText
            android:id="@+id/et_username"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:background="@drawable/editext_selector"
            android:gravity="left|center"
            android:hint="请输入用户名"
            android:maxLength="11"
            android:textColor="@color/black"
            android:textSize="17sp" />
    </LinearLayout>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="40dp"
        android:layout_marginTop="10dp"
        android:orientation="horizontal">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:gravity="center"
            android:text="密 码:"
            android:textColor="@color/black"
            android:textSize="17sp" />
        <EditText
            android:id="@+id/et_password"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:background="@drawable/editext_selector"
            android:gravity="left|center"
            android:hint="请输入密码"
            android:inputType="numberPassword"
            android:maxLength="6"
            android:textColor="@color/black"
            android:textSize="17sp" />
    </LinearLayout>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="10dp" >
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:gravity="center"
            android:text="头 像:"
            android:textColor="@color/black"
            android:textSize="17sp" />
        <ImageView
            android:id="@+id/iv_face"
            android:layout_width="120dp"
            android:layout_height="120dp"
            android:layout_marginLeft="5dp"
            android:scaleType="fitXY"
            android:src="@drawable/add_pic" />
    </LinearLayout>
    <Button
        android:id="@+id/btn_register"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="注册"
        android:textColor="@color/black"
        android:textSize="17sp" />
    <TextView
        android:id="@+id/tv_result"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textColor="@color/black"
        android:textSize="17sp" />
</LinearLayout>

创作不易 觉得有帮助请点赞关注收藏~~~

相关文章
|
11天前
|
SQL 监控 安全
构筑数字堡垒:网络安全与信息保护的深层剖析
【4月更文挑战第9天】在数字化时代,网络安全和信息安全已成为维护个人隐私、企业数据和国家安全不可或缺的一环。本文深入探讨了网络安全漏洞的形成机理、加密技术的进展,以及提升安全意识的重要性。通过对现有安全挑战的分析,提出了一系列创新的防御策略,并强调了构建一个全面的信息保护体系的必要性。
|
19天前
|
存储 安全 网络安全
云端防御战线:云计算环境下的网络安全与信息保护
在信息技术迅猛发展的今天,云计算作为支撑数字转型的重要基石,其安全性牵动着企业生存与发展的命脉。本文深入探讨了云计算环境中面临的安全威胁和挑战,并提出了一系列创新的安全策略和技术解决方案。通过综合分析公有云、私有云以及混合云服务模型中的安全需求,文章构建了一个多层次、全方位的网络安全防护体系。此外,针对数据加密、身份验证、访问控制等关键技术进行了深入剖析,旨在为读者提供一套系统的信息安全保护指南,确保在享受云计算带来的便利时,数据和资源的安全性不被妥协。
35 8
|
22天前
|
Java Android开发
Android 开发获取通知栏权限时会出现两个应用图标
Android 开发获取通知栏权限时会出现两个应用图标
12 0
|
1天前
|
存储 安全 网络安全
构筑安全之盾:云计算环境下的网络安全与信息保护策略
【4月更文挑战第19天】随着云计算技术的飞速发展,企业和个人越来越依赖于云服务来存储、处理和交换数据。然而,这种便利性背后隐藏着潜在的安全风险。本文深入探讨了在云计算背景下,如何通过综合性的安全措施和策略来强化网络安全防护,确保数据的完整性、可用性和机密性。我们将分析当前面临的主要安全挑战,并基于最新的技术进展提出相应的解决方案,以期达到有效防御外部威胁和内部漏洞的目的。
9 4
|
1天前
|
监控 安全 算法
数字堡垒的构建者:网络安全与信息保护的现代策略
【4月更文挑战第19天】在信息化快速发展的今天,网络安全和信息安全已成为维护社会稳定、保障个人隐私和企业商业秘密的关键。本文将深入探讨网络安全漏洞的成因、加密技术的进展以及提升安全意识的重要性,旨在为读者提供一套综合性的网络防护策略,以应对日益猖獗的网络威胁。
4 1
|
3天前
|
监控 安全 网络安全
云端防御战线:云计算中的网络安全与信息保护策略
【4月更文挑战第17天】 随着企业逐渐将重心转向云服务,云计算已经成为现代信息技术架构中不可或缺的一部分。然而,这种转变也带来了新的挑战——如何确保在公共、私有或混合云环境中的数据安全和网络防护。本文探讨了云计算平台下的网络安全策略与实施措施,包括最新的加密技术、身份验证机制以及入侵检测系统。同时,分析了信息安全管理在维护数据完整性、保障用户隐私及符合法规要求方面的重要性。通过综合考量技术手段与管理策略,本文旨在为读者提供一份全面的云计算安全指南。
13 5
|
5天前
|
存储 安全 网络安全
云端防御:在云计算时代维护网络安全与信息完整性
【4月更文挑战第15天】 随着企业和个人用户日益依赖云服务,云计算环境的安全性已成为技术发展的一个关键挑战。本文探讨了云计算平台面临的安全威胁、信息安全的关键策略以及实施有效防护措施的必要性。我们将分析数据加密、身份验证和访问控制等核心技术,并讨论如何通过综合方法保护云资源以应对不断演变的网络攻击。
12 2
|
7天前
|
存储 SQL 安全
网络防线的构筑者:洞悉网络安全与信息保护之道
【4月更文挑战第13天】 随着信息技术的蓬勃发展,网络已成为日常生活和工作不可或缺的一部分。然而,伴随便利的同时,网络安全威胁也日益猖獗,从个人信息泄露到企业数据被盗,安全事件频发。本文将深入探讨网络安全领域的关键组成部分:网络漏洞、加密技术以及安全意识,旨在为读者提供全面的安全防护策略和技术应用知识,助力个人和组织在数字世界中筑起坚固的防线。
|
8天前
|
人工智能 安全 网络安全
云端守卫:云计算环境中的网络安全与信息保护策略
【4月更文挑战第12天】 随着企业与个人日益依赖云服务,数据存储、处理和流通的边界愈发模糊。本文探讨了在动态且复杂的云计算环境中,如何通过创新的安全技术和策略来维护网络安全和保障信息完整性。重点分析了包括身份认证、数据加密、访问控制及入侵检测等在内的关键安全措施,并提出了多层次防御模型,以增强云服务用户的信心,同时促进云计算生态系统的健康发展。
|
9天前
|
存储 安全 网络安全
云端防御:云计算环境下的网络安全与信息保护策略
【4月更文挑战第11天】 随着企业和个人用户日益依赖云服务,其数据和应用程序的安全性成为不可忽视的挑战。本文深入探讨了在云计算环境中维护网络安全和信息保护的关键技术和最佳实践。通过分析当前的安全威胁、漏洞以及针对云平台的攻击手段,我们提出了一系列强化云服务安全性的策略,包括加密技术的应用、身份和访问管理、数据完整性监控、以及安全事件响应计划。此外,本文还讨论了合规性和隐私保护在云服务中的重要性,并提供了对未来云计算与网络安全发展趋势的展望。
10 0