常见的几种文件下载方式
- 通过系统自带的浏览器进行下载
- 通过HTTP文件流进行下载
- 使用系统的Downloader下载
通过浏览器下载
该方法使用简单,但是不保证所有的情况下都奏效,其基本流程代码如下:
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
//String url 为要下载的文件链接,自行定义
intent.setData(Uri.parse(url));
startActivity(intent);
PS:一旦下载的链接指向为图片、文本等浏览器可以直接打开的文件类型时,该方法的执行结果就是打开系统默认的浏览器进行内容显示,而不是进行下载操作
实际运行效果
正例:下载软件安装包时(浏览器无法查看,默认以下载的方式)
反例:当想要下载图片时(浏览器可以查看,默认打开预览)
以文件流方式下载
使用该方法下载的好处就是我们可以对下载的细节进行自定义的处理,如已下载文件在不同百分比我们可以有不同的操作等等。
try {
//String url 为要下载的文件链接,自行定义
HttpURLConnection urlConnection = (HttpURLConnection) new URL(url).openConnection();
//验证下载链接是否有效
//具体详细的HTTP状态码对照可以参照:http://tool.oschina.net/commons?type=5
if (200 == urlConnection.getResponseCode()) {
HttpPost post = new HttpPost(url);
HttpParams httpParams = new BasicHttpParams();
HttpConnectionParams.setConnectionTimeout(httpParams, 3000);
HttpClient httpClient = new DefaultHttpClient(httpParams);
//获取指向该链接内容的输入流
InputStream inputStream = httpClient.execute(post).getEntity().getContent();
FileOutputStream fileOutputStream = new FileOutputStream(new File("文件保存的地址+名称"));
byte[] buffer = new byte[4096];
int length = 0;
//!=-1表示文件流没有结束,用while循环保证读取完全部内容
while (-1 != (length = inputStream.read(buffer))) {
fileOutputStream.write(buffer, 0, length);
}
fileOutputStream.flush();//将缓冲区的数据写到文件中
inputStream.close();
fileOutputStream.close();
}
} catch (Exception e) {
e.printStackTrace();
}
PS:要通过动态的方法获取外部存储的根目录,通过函数调用:
Environment.getExternalStorageDirectory()
PPS:
执行网络请求需要权限:
<uses-permission android:name="android.permission.INTERNET"/>
向外部存储写文件需要权限:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
PPPS:不要在主线程中执行以上操作
使用系统的Downloader下载
上面两种方法都是简单粗暴,但是,我还是要说但是,前两种方法还是稍稍显得有点low,现在要介绍的这种方法虽然用起来稍稍复杂,但是看起来还真是高端大气上档次(陶醉脸)
使用系统的下载器有以下的几个好处:
1. 方便系统对下载内容的管理
2. 省去自己编写对下载进度查看的麻烦
3. 该方式可以降低系统下载类与程序操作类之间的耦合度
4. 不要重复发明轮子,使用现成的类可以减少BUG发生的几率
唯一不足的地方就是将下载操作完全托管于第三方,我们对下载的细节无从得知,我们只能监听系统下载完成操作(ACTION_DOWNLOAD_COMPLETE
)、点击系统提供的下载进度条(ACTION_NOTIFICATION_CLICKED
)和查看下载进入页面(ACTION_VIEW_DOWNLOADS
)。
S1. 相关变量的定义
long downloadTaskID; //下载任务的唯一编号标示
DownloadManager downloadManager; //看名字就知道什么意思了 =。=
PS:关于downloadTaskID的API解释:an ID for the download, unique across the system. This ID is used to make future calls related to this download.
S2. 注册下载完成广播的Receiver[不需要监测下载完成状态的可以略过]
//重写广播的接收事件相应
BroadcastReceiver receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
//只把用户在该Activity中新建的下载任务筛选出来,仅限一个
//如果是多个还得把downloadTaskID保存到一个List当中再进行筛选
Query query = new Query();
query.setFilterById(downloadTaskID);
Cursor cursor = downloadManager.query(query);
if (cursor.moveToNext() && DownloadManager.STATUS_SUCCESSFUL == cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS))) {
//获得下载文件存储的本地路径
String localFileName = cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_FILENAME));
//接下来要进行的操作可自行定义
//可以根据文件类型进行打开,编辑操作等blablabla...
//典型应用:软件升级,下载更新包,然后安装,具体实现代码如下(保证下载的文件是apk类型)
/*
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.parse("file://" + localFileName), "application/vnd.android.package-archive");
startActivity(intent);
*/
}
}
};
//只接收系统下载完成的广播通知
//正因为如此,在receiver的onReceive方法中不需要再对intent.getAction()进行判断筛选
registerReceiver(receiver, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
S3. 启动下载操作
ApplicationInfo applicationInfo = getPackageManager().getApplicationInfo("com.android.providers.downloads", 0);
//当系统Downloader可用时才进行下载操作
if (applicationInfo.enabled) {
downloadManager = (DownloadManager) getSystemService(DOWNLOAD_SERVICE);
Request request = new Request(Uri.parse("要下载的文件链接"));
downloadTaskID = downloadManager.enqueue(request);
} else {
Toast.makeText(this, "系统下载工具不可用", Toast.LENGTH_SHORT).show();
}
PS:上述代码的运行上下文是
Activity
实际运行效果
Notification查看下载进度
系统下载管理界面查看下载进度