Android Retrofit下载文件进度
在本教程中,我们将创建一个Android应用程序,该应用程序使用Retrofit从URL下载文件。
要了解翻新的基础知识,请访问本教程。
Android改造下载文件
我们可以通过以下方式创建改造调用以下载文件:
@GET Call<ResponseBody> downloadFileWithc(@Url String urlString);
我们可以传递要下载的文件的URL。
如果我们要下载资源中存在的文件,则可以执行以下操作:
@GET("/resource/path_to_file_with_extension")
Call<ResponseBody> downloadFileStatic();
建议在@GET顶部使用@Streaming批注来下载文件。
否则,翻新会将整个文件移到内存中。
使用@Streaming可以在不占用内存的情况下当前访问字节。
当使用@ Streaming时,必须将写入下载数据的代码添加到单独的线程中。
使用enqueue方法,我们可以启动请求。
其中,我们需要创建一个AsyncTask或者使用RxJava。
在本教程中,我们将使用前者。
在下面将要构建的android应用程序中,我们将在ProgressBar上显示文件下载进度。
项目设置
将以下依赖项添加到您应用的build.gradle中:
implementation 'com.squareup.retrofit2:retrofit:2.3.0' implementation 'com.squareup.okhttp3:okhttps:3.10.0'
在列表中添加以下权限:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" <uses-permission android:name="android.permission.INTERNET"
以下是我们的项目结构的外观:
代码
下面给出了" activity_main.xml"布局的代码:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="https://schemas.android.com/apk/res/android"
xmlns:app="https://schemas.android.com/apk/res-auto"
xmlns:tools="https://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:id="@+id/txtProgressPercent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Downloaded 0%"
android:textColor="@color/colorAccent"
android:textStyle="bold"
android:textAppearance="@style/Base.TextAppearance.AppCompat.Display1"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
<ProgressBar
android:id="@+id/progressBar"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:layout_marginTop="16dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/txtProgressPercent"
<Button
android:id="@+id/button"
style="@style/ButtonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="DOWNLOAD FILE"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/progressBar"
</android.support.constraint.ConstraintLayout>
我们在styles.xml中的按钮上设置了样式。
下面给出了RetrofitInterface.java类的代码:
package com.theitroad.androidretrofitdownloadfileprogress;
import okhttp3.ResponseBody;
import retrofit2.Call;
import retrofit2.http.GET;
import retrofit2.http.Streaming;
import retrofit2.http.Url;
public interface RetrofitInterface {
@Streaming
@GET
Call<ResponseBody> downloadFileByUrl(@Url String fileUrl);
}
MainActivity.java类的代码如下:
package com.theitroad.androidretrofitdownloadfileprogress;
import android.Manifest;
import android.content.pm.PackageManager;
import android.os.AsyncTask;
import android.os.Environment;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.util.Pair;
import android.view.View;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import okhttp3.OkHttpClient;
import okhttp3.ResponseBody;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.Retrofit;
public class MainActivity extends AppCompatActivity {
TextView txtProgressPercent;
ProgressBar progressBar;
Button btnDownloadFile;
DownloadZipFileTask downloadZipFileTask;
private static final String TAG = "MainActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
askForPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE, 101);
txtProgressPercent = findViewById(R.id.txtProgressPercent);
progressBar = findViewById(R.id.progressBar);
btnDownloadFile = findViewById(R.id.button);
btnDownloadFile.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
downloadZipFile();
}
});
}
private void downloadZipFile() {
RetrofitInterface downloadService = createService(RetrofitInterface.class, "https://github.com/");
Call<ResponseBody> call = downloadService.downloadFileByUrl("anupamchugh/AnimateTextAndImageView/archive/master.zip");
call.enqueue(new Callback<ResponseBody>() {
@Override
public void onResponse(Call<ResponseBody> call, final Response<ResponseBody> response) {
if (response.isSuccessful()) {
Log.d(TAG, "Got the body for the file");
Toast.makeText(getApplicationContext(), "Downloading...", Toast.LENGTH_SHORT).show();
downloadZipFileTask = new DownloadZipFileTask();
downloadZipFileTask.execute(response.body());
} else {
Log.d(TAG, "Connection failed " + response.errorBody());
}
}
@Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
t.printStackTrace();
Log.e(TAG, t.getMessage());
}
});
}
public <T> T createService(Class<T> serviceClass, String baseUrl) {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(baseUrl)
.client(new OkHttpClient.Builder().build())
.build();
return retrofit.create(serviceClass);
}
private class DownloadZipFileTask extends AsyncTask<ResponseBody, Pair<Integer, Long>, String> {
@Override
protected void onPreExecute() {
super.onPreExecute();
}
@Override
protected String doInBackground(ResponseBody... urls) {
//Copy you logic to calculate progress and call
saveToDisk(urls[0], "theitroad-project.zip");
return null;
}
protected void onProgressUpdate(Pair<Integer, Long>... progress) {
Log.d("API123", progress[0].second + " ");
if (progress[0].first == 100)
Toast.makeText(getApplicationContext(), "File downloaded successfully", Toast.LENGTH_SHORT).show();
if (progress[0].second > 0) {
int currentProgress = (int) ((double) progress[0].first/(double) progress[0].second * 100);
progressBar.setProgress(currentProgress);
txtProgressPercent.setText("Progress " + currentProgress + "%");
}
if (progress[0].first == -1) {
Toast.makeText(getApplicationContext(), "Download failed", Toast.LENGTH_SHORT).show();
}
}
public void doProgress(Pair<Integer, Long> progressDetails) {
publishProgress(progressDetails);
}
@Override
protected void onPostExecute(String result) {
}
}
private void saveToDisk(ResponseBody body, String filename) {
try {
File destinationFile = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), filename);
InputStream inputStream = null;
OutputStream outputStream = null;
try {
inputStream = body.byteStream();
outputStream = new FileOutputStream(destinationFile);
byte data[] = new byte[4096];
int count;
int progress = 0;
long fileSize = body.contentLength();
Log.d(TAG, "File Size=" + fileSize);
while ((count = inputStream.read(data)) != -1) {
outputStream.write(data, 0, count);
progress += count;
Pair<Integer, Long> pairs = new Pair<>(progress, fileSize);
downloadZipFileTask.doProgress(pairs);
Log.d(TAG, "Progress: " + progress + "/" + fileSize + " >>>> " + (float) progress/fileSize);
}
outputStream.flush();
Log.d(TAG, destinationFile.getParent());
Pair<Integer, Long> pairs = new Pair<>(100, 100L);
downloadZipFileTask.doProgress(pairs);
return;
} catch (IOException e) {
e.printStackTrace();
Pair<Integer, Long> pairs = new Pair<>(-1, Long.valueOf(-1));
downloadZipFileTask.doProgress(pairs);
Log.d(TAG, "Failed to save the file!");
return;
} finally {
if (inputStream != null) inputStream.close();
if (outputStream != null) outputStream.close();
}
} catch (IOException e) {
e.printStackTrace();
Log.d(TAG, "Failed to save the file!");
return;
}
}
private void askForPermission(String permission, Integer requestCode) {
if (ContextCompat.checkSelfPermission(MainActivity.this, permission) != PackageManager.PERMISSION_GRANTED) {
if (ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this, permission)) {
ActivityCompat.requestPermissions(MainActivity.this, new String[]{permission}, requestCode);
} else {
ActivityCompat.requestPermissions(MainActivity.this, new String[]{permission}, requestCode);
}
} else if (ContextCompat.checkSelfPermission(MainActivity.this, permission) == PackageManager.PERMISSION_DENIED) {
Toast.makeText(getApplicationContext(), "Permission was denied", Toast.LENGTH_SHORT).show();
}
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (ActivityCompat.checkSelfPermission(this, permissions[0]) == PackageManager.PERMISSION_GRANTED) {
if (requestCode == 101)
Toast.makeText(this, "Permission granted", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(this, "Permission denied", Toast.LENGTH_SHORT).show();
}
}
}
在上面的代码中,我们正在下载GitHub存储库zip文件。
我们在上面的代码中进行以下操作:
运行时权限–我们需要此权限才能将文件保存在手机存储中。
使用OkHttp构建改造服务
使用
response.body()从Async中的url下载文件。在AsyncTask内部,我们创建一个公共方法
doProgress,其中调用AsyncTask方法publishProgress()。publishProgress从doInBackground触发AsyncTask的ʻonProgressUpdate()方法。
这样我们就可以确定文件下载的进度,并在ProgressBar上对其进行更新。
下载的文件路径在内部存储器的downloads文件夹内设置。

