需要源码请点赞关注收藏后评论区留言并且私信~~~
一、使用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>
创作不易 觉得有帮助请点赞关注收藏~~~