前言
DownloadManager是Android2.3(API 9)提供的下载操作,其“处理Http/Https连接并监控连接中的状态变化及系统重启来确保每一个下载任务顺利完成”[1]。DownLoadManager对于后台下载、下载回调、失败重试、断点续传、文件操作等方面都有很好的支持,同时使用简便,对于开发者,在大多数的使用环境中,它都是一个很好的选择。
使用
DownloadManager有两个子类,Request和Query。
- Request类可以设置下载属性,诸如下载地址、文件类型等。
- Query类可以用来查询下载的相关信息,包括下载进度、下载文件地址等。
1.权限配置
DownloadManager的使用需要配置权限为
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
2.下载方法
DownloadManager mDownloadManager = (DownloadManager) getSystemService(DOWNLOAD_SERVICE);//获取下载管理器服务的实例
DownloadManager.Request mRequest = new DownloadManager.Request(Uri.parse(url));//创建下载请求并传入下载地址
Long downID = mDownloadManager.enqueue(mRequest);//将下载请求加入下载队列, 返回一个下载ID
3.封装下载请求Request
mRequest.setDestinationInExternalPublicDir("/zhang_download/", url.substring(url.lastIndexOf("/")))// 指定下载路径
.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_MOBILE) // 指定可以在移动网络下下载
.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI) // 可以再wifi下下载
.setMimeType(mimeType) // 设定下载类型为apk
// .addRequestHeader("header", "value") //网络连接的http头
.setTitle("downloadManager下载...") // notification标题
.setDescription("<文件描述>") // notification标题描述
.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED); // notification可见方式
3.1 设置文件下载位置
// 将文件保存在应用所在文件夹下的Download文件夹下,下载的文件会随着应用的卸载而删除
mRequest.setDestinationInExternalFilesDir(context, Environment.DIRECTORY_DOWNLOADS, "file.apk");
// 将文件保存在SD卡"zhang_download"文件夹下,这个文件夹如果不存在会自动创建
mRequest.setDestinationInExternalPublicDir("/zhang_download/", "file.apk");
3.2 指定下载时候的网络类型
设置适当的网络类型,避免用户使用移动流量下载文件(这点很重要啊···)。
// 指定可以在移动网络下下载
mRequest.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_MOBILE);
// 可以在wifi下下载
mRequest.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI);
3.3 设置文件类型(mineType)
下载管理Ui中点击某个已下载完成文件及下载完成点击通知栏提示都会根据mimeType去打开文件。mineType参考表。
// 设置下载的文件类型为.APK安装文件
mRequest.setMimeType("application/vnd.android.package-archive");
3.4 设置网络连接头
// 设置网络连接http头,如User-Agent等
mRequest.addRequestHeader("header", "value");
3.5 设置通知栏样式
.setTitle("downloadManager下载...") // notification标题
.setDescription("<文件描述>") // notification标题描述
.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED); // notification可见方式
对于通知栏的显示模式,可以分为以下几种。
显示方式 | 描述 |
---|---|
VISIBILITY_VISIBLE | Notification在下载时显示,下载完成后关闭(默认方式) |
VISIBILITY_VISIBLE_NOTIFY_COMPLETED | Notification下载时显示,下载完成后不关闭 |
VISIBILITY_HIDDEN | Notification不显示,需要添加权限Android.permission.DOWNLOAD_WITHOUT_NOTIFICATION |
VISIBILITY_VISIBLE_NOTIFY_ONLY_COMPLETION | Notification只有在下载完成时才会显示 |
4.获取下载信息
获取文件下载进度需要使用到Query类。通过Cursor结果集来获取下载信息。
/**
* 获取下载信息
*/
private int getQuery() {
int Percentage; // 下载进度
mQuery = new DownloadManager.Query();
Cursor cursor = mDownloadManager.query(mQuery.setFilterById(downId));
if (cursor != null && cursor.moveToFirst()) {
String address = cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI));
int bytes_downloaded = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR));
int bytes_total = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_TOTAL_SIZE_BYTES));
String title = cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_TITLE));
String description = cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_DESCRIPTION));
String downId = cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_ID));
Percentage = (int) ((bytes_downloaded * 1f) / bytes_total * 100f);
cursor.close();
return Percentage;
}
return 0;
}
通过这样,我们便可以获取文件的下载进度、下载地址等信息。但由于这种方式一次只能获取某一个时间段的下载状态,因此我们需要设定定时器循环查询。同时,我们也可以定义自己的进度条,来显示下载进度。
mTimer = new Timer();
mTimer.schedule(new TimerTask() {
@Override
public void run() {
int Percentage = getQuery();
if (Percentage >= 100) {
cancel();
install(filePath); // 安装APK
}
Message msg = new Message();
msg.what = 1001;
msg.obj = Percentage;
handler.sendMessage(msg);
}
}, 0, 100);
附上完整代码
/**
* 使用downloadManager下载
*/
public class DownManagerActivity extends AppCompatActivity {
private Context context;
private String mimeType = "application/vnd.android.package-archive";
private Button downloadManagerBtn;
private ProgressBar progressBar;
private String url = "http://gdown.baidu.com/data/wisegame/c5ada0a2f33be088/baidushoujizhushouyuan91zhu_16792523.apk";
private DownloadManager mDownloadManager;
private DownloadManager.Request mRequest;
private DownloadManager.Query mQuery;
private Long downId;
private Timer mTimer;
private String filePath;
Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if (msg.what == 1001) {
progressBar.setProgress((Integer) msg.obj);
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_down_manager);
context = this;
initView();
}
private void initView() {
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
toolbar.setTitle("使用DownloadManager下载文件");
toolbar.setTitleTextColor(Color.WHITE);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
finish();
}
});
downloadManagerBtn = (Button) findViewById(R.id.downloadManagerBtn);
downloadManagerBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
download();
mTimer = new Timer();
mTimer.schedule(new TimerTask() {
@Override
public void run() {
int Percentage = getQuery();
if (Percentage >= 100) {
cancel();
install(filePath); // 安装APK
}
Message msg = new Message();
msg.what = 1001;
msg.obj = Percentage;
handler.sendMessage(msg);
}
}, 0, 100);
}
});
progressBar = (ProgressBar) findViewById(R.id.progressBar);
}
/**
* 下载
*/
private void download() {
mDownloadManager = (DownloadManager) getSystemService(DOWNLOAD_SERVICE);
mRequest = new DownloadManager.Request(Uri.parse(url));
mRequest.setDestinationInExternalPublicDir("/zhang_download/", url.substring(url.lastIndexOf("/")))// 指定下载路径
.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_MOBILE) // 指定可以在移动网络下下载
.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI) // 可以再wifi下下载
.setMimeType(mimeType) // 设定下载类型为apk
// .addRequestHeader("header", "value") //网络连接的http头
.setTitle("downloadManager下载...") // notification标题
.setDescription("<文件描述>") // notification标题描述
.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED); // notification可见方式
downId = mDownloadManager.enqueue(mRequest);
}
/**
* 获取下载信息
*/
private int getQuery() {
int Percentage;
mQuery = new DownloadManager.Query();
Cursor cursor = mDownloadManager.query(mQuery.setFilterById(downId));
if (cursor != null && cursor.moveToFirst()) {
String address = cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI));
int bytes_downloaded = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR));
int bytes_total = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_TOTAL_SIZE_BYTES));
String title = cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_TITLE));
String description = cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_DESCRIPTION));
String downId = cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_ID));
Percentage = (int) ((bytes_downloaded * 1f) / bytes_total * 100f);
cursor.close();
return Percentage;
}
return 0;
}
/**
* 安装app
*
* @param path
*/
private void install(String path) {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.parse(path), mimeType);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}