目录
Android 从 2.3 (API9) 开始提供了专门的下载工具DownloadManager(下载管理器)统一管理下载操作。
下载管理器DownloadManager的对象从系统服务DOWNLOAD_SERVICE中获取,具体使用过程分为3步:构建下载请求(Request)、进行下载操作(DownloadManager)和查询下载进度(Query)。
一、构建下载请求-Request
要想使用下载功能,首先得构建一个下载请求(DownloadManager.Request),说明从哪里下载、下载参数是什么、下载的文件保存到哪里等。这个下载请求就是DownloadManager的内部类Request。以下是该类的常用方法:
- DownloadManager构造函数:指定从哪个网络地址下载文件。
- setAllowedNetworkTypes:指定允许下载的网络类型。若同时允许多种网络类型,则可使用竖线“|”把多种网络类型拼接起来。取值为:
- DownloadManager.Request.NETWORK_WIFI WiFi 网络
- DownloadManager.Request.NETWORK_MOBILE 移动网络(手机的数据连接)
- setDestinationInExternalFilesDir:设置下载文件的保存路径(存于程序私有文件夹)。
- setDestinationInExternalPublicDir:设置下载文件的保存路径(存于公共文件夹)。第一个参数为目录类型(主文件夹);第二个参数为主文件夹下的部分文件路径,为仅文件名时不加后缀名,为路径时需加后缀名;另外,如果指定目录已存在同名文件,系统就会将新下载的文件重命名,即在文件名末尾添加“-1” “-2”之类的序号。目录类型(主文件夹)取值如下:
- Environment.DIRECTORY_PICTURES
- Environment.DIRECTORY_DCIM
- Environment.DIRECTORY_MUSIC
- Environment.DIRECTORY_DOWNLOADS
- Environment.DIRECTORY_SCREENSHORT
- addRequestHeader:给 HTTP 请求添加头部参数。如断点续传的Range字头,根据已有字节数续接。
- setMimeType:设置下载文件的媒体类型。一般无须设置,默认是服务器返回的媒体类型。参数为String型,如"text/html",HTML格式;"text/pain",纯文本格式;"image/jpeg",jpg图片格式。
- setTitle:设置通知栏上的消息标题。如果不设置,默认标题就是下载的文件名。
- setDescription:设置通知栏上的消息描述。如果不设置,默认显示系统估算的下载剩余时间。
- setVisibleInDownloadsUi:设置是否显示在系统的下载页面上。
- setNotificationVisibility: 设置通知栏的下载任务可见类型。取值如下:
- DownloadManager.Request.VISIBILITY_HIDDEN 隐藏
- DownloadManager.Request.VISIBILITY_VISIBLE 下载时可见(下载完成后消失)
- DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED 下载进行时与完成后都可见
- DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_ONLY_COMPLETION 只有下载完成后可见
二、进行下载操作-DownloadManager
构建完下载请求才能进行下载的相关操作。以下是DownloadManager的常用方法:
- enqueue:将下载请求加入任务队列中,排队等待下载。该方法返回本次下载任务的编号。
- remove:取消指定编号的下载任务。
- openDownloadedFile:打开下载完成的文件。
- getMimeTypeForDownloadedFile:获取下载完成文件的媒体类型。
- query:根据查询请求获取符合条件的结果集游标Curosr。
三、查询下载进度-Query
虽然下载进度可在通知栏上查看,但是如果App自身也想了解当前的下载进度,就要调用下载管理器的query方法。该方法的输入参数是一个Query对象,返回结果集的Cursor对象,这里的Cursor用法与SQLite中的Cursor 一样。
以下是Query类的常用方法说明:
- setFilterByld:根据编号过滤下载任务。
- setFilterByStatus:根据状态过滤下载任务。
设置完查询请求,即可调用 DownloadManager 对象的query方法,获得结果集的游标对象Cusor。该游标中包含下载任务的完整字段信息,主要下载字段的取值如下:
- DownloadManager.COLUMN_LOCAL_FILENAME 下载文件的本地保存路径
- DownloadManager.COLUMN_MEDIA_TYPE 下载文件的媒体类型
- DownloadManager.COLUMN_TOTAL_SIZE_BYTES 下载文件的总大小
- DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR 已下载的文件大小
- DownloadManager.COLUMN_STATUS 下载状态
下载状态的取值说明:
- STATUS_PENDING 挂起,即正在等待
- STATUS_RUNNING 运行中
- STATUS_PAUSED 暂停
- STATUS_SUCCESSFUL 成功
- STATUS_FAILED 失败
//方法总结
//创建下载请求
DownloadManager.Request request=new DownloadManager.Request(Uri.parse(urlString));
//设置允许下载的网络类型
request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI|DownloadManager.Request.NETWORK_MOBILE);
//设置保存文件地址
//公共文件夹-第一个参数为文件夹类型-第二个参数为主文件夹下的部分文件路径,为仅文件名时不加后缀名,为路径时需加后缀名
request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS,"MyDownloadManagerTest/myTestDownload.png");
//app私有文件夹
//request.setDestinationInExternalFilesDir(MainActivity.this, Environment.DIRECTORY_DOWNLOADS,"myTestDownload");
//添加HTTP请求头参数,如断点续接Range字段(使用已有字节数续接)
//request.addRequestHeader("Range", "bytes=" + downloadedBytes + "-");
//设置下载文件的媒体类型,一般无需设置,默认服务器返回的媒体类型
//request.setMimeType("image/jpeg");
//设置通知栏标题,无设置默认下载的文件名
request.setTitle("DownloadManager下载测试");
//设置通知栏内容,无设置默认估算剩余时间
//request.setDescription("通知栏内容");
//设置是否显示在系统的下载页面上
request.setVisibleInDownloadsUi(true);
//设置通知栏显示类型
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
//获取下载管理器
DownloadManager downloadManager= (DownloadManager) getSystemService(DOWNLOAD_SERVICE);
//下载
//将下载请求添加到任务队列
long downloadId=downloadManager.enqueue(request);
//取消下载
downloadManager.remove(downloadId);
//获取下载完成文件的媒体类型
String fileString=downloadManager.getMimeTypeForDownloadedFile(downloadId);
//查询下载情况
//获取Query
DownloadManager.Query query=new DownloadManager.Query();
//根据下载ID过滤
query.setFilterById(downloadId);
//根据下载状态过滤
query.setFilterByStatus(DownloadManager.STATUS_RUNNING);
//查询-Cursor的使用方法与SEQLite一致
Cursor cursor=downloadManager.query(query);
四、事件广播监听
系统的下载服务还提供3种下载事件,开发者可通过注册广播接收者监听对应的广播消息进行相应的处理。3种下载事件说明如下:
1.下载完成事件
在下载完成时,系统会发出名为 DownloadManager.ACTION_DOWNLOAD_COMPLETE(值为字符串 android.intent.action.DOWNLOAD_COMPLETE)的广播,因此可注册一个该广播的接收器,用来判断当前任务是否已下载完毕,并进行后续的业务处理。
2.下载进行时的通知栏点击事件
在下载过程中,只要用户点击通知栏上的下载任务,系统就会发出行为名称是DownloadManager.ACTION_NOTIFICATION_CLICKED(值为字符串 androidintent.action.DOWNLOAD_NOTIFICATION_CLICKED)的广播,可注册该广播的接收器进行相关处理,比如跳转到该任务的下载进度页面等。
3.下载完成后的通知栏点击事件
下载完成后点击触发的是系统的 Intent.ACION_VIEW(浏览行为)。对于浏览行为,系统会根据媒体类型自动寻找对应App打开。因此,如果开发者要控制此时的点击行为,可以调用Request对象的setMimeType方法设置媒体类型,这样 Android 就会按照这个类型打开相应的 APP。
public class MyReceiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
//获取活动
String action=intent.getAction();
//下载完成触发广播
if(action.equals(DownloadManager.ACTION_DOWNLOAD_COMPLETE)){
//获取下载编号
//getLongExtra第二个参数为默认值
long downloadId=intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID,-1);
}
//点击通知(未下载完)触发通知
else if(action.equals(DownloadManager.ACTION_NOTIFICATION_CLICKED)){
//获取全部下载编号
long[] downloadIds=intent.getLongArrayExtra(DownloadManager.EXTRA_DOWNLOAD_ID);
//检查是否是本应用下载的
for(long downloadId:downloadIds){
//... ...
}
}
//点击通知(下载完)触发通知
else if (action.equals(Intent.ACTION_VIEW)) {
//获取下载编号
long downloadId=intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID,-1);
}
}
}
五、暂停、继续下载
DownloadManager类不提供直接的暂停下载的方式。它只提供了启动下载和取消下载的方法。
如果想要实现下载的暂停功能,可以使用DownloadManager提供的remove()方法取消下载任务。然后,可以记录已下载的字节数和文件URL等信息,以便稍后重新启动下载时可以通过设置HTTP字头的Range字段恢复下载进度。
需要注意的是,为了支持断点续传,服务器必须能够处理并正确响应Range字段,返回恰当范围的数据。同时,如果服务器不支持断点续传或不满足范围请求,它可能会忽略Range字段并返回完整的文件。因此,断点续传的成功与否也取决于服务器的支持。
private long downloadId; // 用于记录下载任务的ID
private boolean isPaused = false; // 标记下载是否被暂停
/**
* 第一次下载时参数使用0
*/
private void startDownload(int downloadedBytes) {
// 创建下载请求
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(urlString));
// 根据已下载的字节数设置请求头Range字段,以实现断点续传功能
request.addRequestHeader("Range", "bytes=" + downloadedBytes + "-");
// 其他设置...
// 获取下载管理器
DownloadManager downloadManager = (DownloadManager) getSystemService(DOWNLOAD_SERVICE);
// 下载执行
downloadId = downloadManager.enqueue(request);
}
private void pauseDownload() {
// 取消下载任务
DownloadManager downloadManager = (DownloadManager) getSystemService(DOWNLOAD_SERVICE);
downloadManager.remove(downloadId);
// 记录已下载的字节数()
long downloadedBytes = getDownloadedBytes(downloadId);
// 保存已下载的字节数及其他信息至本地,以便稍后恢复下载
isPaused = true;
}
private void resumeDownload() {
// 恢复下载,重新发起下载请求
isPaused = false;
// 从本地获取已下载的字节数及其他信息
// long downloadedBytes = getSavedDownloadedBytes();
startDownload(dowbloadedBytes);
}
private int getDownloadedBytes(downloadId){
int retI=0;
//获取Query
DownloadManager.Query query=new DownloadManager.Query();
//根据下载ID过滤
query.setFilterById(downloadId);
// 获取下载管理器
DownloadManager downloadManager = (DownloadManager) getSystemService(DOWNLOAD_SERVICE);
//查询-Cursor的使用方法与SEQLite一致
Cursor cursor=downloadManager.query(query);
if(cursor.getCount()>0){
cursor.moveToNext();
retI=cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR));
}
return retI;
}
六、基础使用案例代码
public class MainActivity extends AppCompatActivity {
private String urlString="https://bkimg.cdn.bcebos.com/pic/00e93901213fb80ee7dc88b530d12f2eb9389447?x-bce-process=image/resize,m_lfit,w_536,limit_1/quality,Q_70";
private URL url=null;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//获取控件
Button button=findViewById(R.id.button);
//获取URL
try {
url=new URL(urlString);
} catch (MalformedURLException e) {
throw new RuntimeException(e);
}
//添加监听器
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
if(!getNetworkState(MainActivity.this)){
Toast.makeText(MainActivity.this,"无网络",Toast.LENGTH_SHORT).show();
return;
}
Toast.makeText(MainActivity.this,"开始下载",Toast.LENGTH_SHORT).show();
startDownload();
}
});
}
/**
* 获取网络状态
* @param context
* @return true连接 false未连接
*/
private boolean getNetworkState(Context context){
ConnectivityManager cm= (ConnectivityManager) context.getSystemService(CONNECTIVITY_SERVICE);
NetworkInfo networkInfo=cm.getActiveNetworkInfo();
if(networkInfo==null){
return false;
}
return true;
}
/**
* 开始下载-DownloadManager
*/
private void startDownload(){
//创建下载请求
DownloadManager.Request request=new DownloadManager.Request(Uri.parse(urlString)); request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI|DownloadManager.Request.NETWORK_MOBILE);
request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS,"myTestDownload");
request.setTitle("DownloadManager下载测试");
request.setVisibleInDownloadsUi(false);
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
//获取下载管理器
DownloadManager downloadManager= (DownloadManager) getSystemService(DOWNLOAD_SERVICE);
//将下载请求添加到任务对列
long downloadId=downloadManager.enqueue(request);
}
}
tag:保存文件;网络下载;存储;保存;下载;内存;路径