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

news2024/11/16 3:52:33

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

一、使用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>

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/31712.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C++:指针:void*指针(跳跃力未定的指针)

先分享一段代码&#xff0c;觉得很有意思 #include<iostream> void* say_hello(void* args){std::cout<< "Hello world"<< std::endl;return 0; } 上面这段代码&#xff0c;我们看到函数的返回值类型竟然是 void* ,形参也是 void* &#xff0c…

限时开源,一份“扭转乾坤”的与时俱进的1700页Java八股文

今天在某客看到一个程序员自述&#xff0c;内容如下&#xff1a; 人到三十&#xff0c;公司效益不好被裁员&#xff0c;两个月时间面了三十几家&#xff0c;一直不是很顺利&#xff0c;面试问八股&#xff0c;根本答不上来。前期不信邪&#xff0c;正常投简历正常面试&#xf…

如何借助现有股票量化交易平台编写策略和回测分析

每个交易日的股票都会上涨或者下跌&#xff0c;在这个过程中笔者们偶尔会想针对部分股票进行股价的涨跌幅进行监控&#xff0c;或者自动进行交易&#xff0c;在这个需求前提下&#xff0c;现有券商、股票分析软件都会带有机器人自动交易策略功能&#xff0c;大部分都需要收费或…

web网页大作业——基于HTML+CSS+JavaScript制作摄影之家网站

&#x1f389;精彩专栏推荐&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业…

OAuth2 的授权流程

文章目录&#x1f4d6; OAuth2 的授权流程&#x1f4d1; 参与的角色&#x1f4d1; 授权流程&#x1f4d1; 授权许可 Authorization Grant&#x1f4d1; 直白话 OAuth2 流程&#x1f4d6; OAuth2 的授权流程 &#x1f4d1; 参与的角色 1️⃣ Resource Owner资源所有者&#xf…

如何监听电脑屏幕是否发生切换

目录 1.屏幕监听的原理&#xff1a; 2.创建项目 3.离开计时 1.屏幕监听的原理&#xff1a; 为什么可以监听浏览器窗口的切换呢&#xff1f;那就是利用了浏览器的visibilitychange属性&#xff0c;MDN的介绍对visibilitychnge的介绍是&#xff1a; 当其选项卡的内容变得可见或…

nginx(六十二)proxy模块(三)接收用户请求的包体

一 接收用户请求包体 nginx读取请求体的源码分析 说明&#xff1a; 虽然是被http core核心框架处理,但是被proxy反向代理模块使用重点&#xff1a; 哪些指令控制接收request body的行为? ① proxy_request_buffering 控制&#xff1a; nginx接收客户端 request body的方式…

【优化选址】遗传算法求解物流配送中心选址【含Matlab源码 1917期】

⛄一、物流选址简介 1 引言 配送中心是物流系统网络中的关键节点和重要的基础设施&#xff0c;在整个物流系统网络规划中起着枢纽性的作用[1]。快递物流配送中心选址是指在具有若干个发件网点或者若干个收件网点的物流配送区域内&#xff0c;综合考虑物流运输成本、配送中心建…

【计算机网络】Servlet API重点知识汇总

目录 1.HttpServlet&#xff1a; 2.HttpServletRequest&#xff1a; 3.HttpServletRequest代码实例&#xff1a; 3.1.打印请求的内容&#xff1a; 3.2.获取请求中的重要参数 &#xff08;query string中的值&#xff09;&#xff1a; 3.3.获取请求中的重要参数 &#x…

关于循环浅析

从c,c,python,scala到java&#xff0c;简单接触了这样一些编程语言&#xff0c;对于它们的基本语法中的循环想做个总结。 一、c&#xff0c;c C语言for循环&#xff08;for语句&#xff09;详解 (biancheng.net) //这个链接比较详细&#xff0c;本人也从中摘取了一些知识点。…

【javaEE】网络原理(传输层Part2)

努力经营当下&#xff0c;直至未来明朗&#xff01; 文章目录前言TCP相关机制4. 【滑动窗口】5.【流量控制】6.【拥塞控制】总结前言 一个人最大的痛苦来源于对自己无能的愤怒&#xff01; Hi&#xff0c;这里是不想秃头的宝贝儿&#xff01; 本文主要内容是 传输层中TCP相关…

什么是SRM,SRM有什么作用,SRM主要用途是什么?

简道云SRM管理应用一、什么是SRM? SRM是 Supplier Relationship Management 的英文缩写&#xff0c;即供应商关系管理。 SRM的最基本内容包括供应商分类选择、战略关系发展、供应商谈判和供应商绩效评价四个方面。 SRM是用来改善企业与供应商的关系&#xff0c;它是一种致力…

了解一下OAuth2.0到底是什么,有图解有案例

理论 OAuth是一个关于授权&#xff08;authorization&#xff09;的开放网络标准&#xff0c;用来授权第三方应用获取用户数据&#xff0c;是目前最流行的授权机制&#xff0c;它当前的版本是2.0。 应用场景 假如你正在“网站A”上冲浪&#xff0c;看到一篇帖子表示非常喜欢…

Python交互Mysql数据库基本操作

安装pymysql第三方包 1. 安装pymysql 2. 查看安装情况 ​ 3. 卸载pymysq ​ Pymysql的使用 1. 导包 ​ 2. 创建和mysql服务端的连接对象 ​ 3. 获取游标对象 ​ 4. 执行sql语句 ​ 5. 获取查询结果集 ​ 6. 将增加和修改操作提交到数据库 7. 回滚数据 8. 关闭游标对象 …

【网页设计】期末大作业html+css(体育网站--足球 6页 )

⛵ 源码获取 文末联系 ✈ Web前端开发技术 描述 网页设计题材&#xff0c;DIVCSS 布局制作,HTMLCSS网页设计期末课程大作业 | 校园篮球网页设计 | 足球体育运动 | 体育游泳运动 | 兵乓球 | 网球 | 等网站的设计与制作 | HTML期末大学生网页设计作业 HTML&#xff1a;结构 CSS&…

mTD-SCDMA与TD-LTE双网络垂直切换matlab仿真

目录 1.算法描述 2.仿真效果预览 3.MATLAB部分代码预览 4.完整MATLAB程序 1.算法描述 TD-SCDMA与TD-LTE共覆盖的范围内覆盖半径1000m&#xff1b; TD-SCDMA中心坐标(0,0)&#xff0c;覆盖半径1000m&#xff1b; 两个TD-LTE基站的中心坐标为&#xff08;150&#xff0c;0…

刚毕业被骗去了小公司,天天“取数做表”,后悔没早点用上这工具

经常看到年轻人提问“究竟是去大公司打杂好&#xff0c;还是去小公司磨练好&#xff1f;”这个问题我年轻的时候也想过&#xff0c;当时觉得去大公司只能当螺丝钉&#xff0c;做按部就班的工作&#xff0c;于是毅然决然放弃了大厂offer去了一家IT部门只有3个人的公司。当时我在…

通过电子文档管理改善患者体验和办公效率

通过电子文档管理改善患者体验和办公效率 在不远的过去&#xff0c;手动输入医疗信息和物理归档系统是所有医疗办公室的标准操作程序。医生和工作人员别无选择&#xff0c;只能写下信息&#xff0c;然后手动将数据输入办公系统。 当要求所有从业者使用电子病历的授权作为“患…

亚马逊买家号造成被封的原因有哪些?

现在很多人反馈说亚马逊买家号太容易被封了&#xff0c;去下单时都不知道什么情况都就砍单&#xff0c;账号登录不上了&#xff0c;而关于亚马逊买家号被封这个问题&#xff0c;不是一两个因素就能决定的&#xff0c;那么亚马逊买家号造成被封的原因有哪些&#xff1f; 1、账号…

虚拟机三种网络模式

基本知识 ipconfig查看信息。 网关(Gateway)又称网间连接器、协议转换器。是你连接到的上层节点的地址。 ip地址是你本身的地址&#xff08;如果是路由器分配的 那么是路由器所构建的内网地址&#xff09; 网卡&#xff1a;需要网卡才能连接其他设备 是设备端的 交换机&#x…