Android中如何下载文件并显示下载进度

原文地址:http://jcodecraeer.com/a/anzhuokaifa/androidkaifa/2014/1125/2057.html

这里主要讨论三种方式:AsyncTask、Service和使用DownloadManager

一、使用AsyncTask并在进度对话框中显示下载进度

这种方式的优势是你可以在后台执行下载任务的同时,也可以更新UI(这里我们用progress bar来更新下载进度)

下面的代码是使用的例子

 1 // declare the dialog as a member field of your activity
 2 ProgressDialog mProgressDialog;
 3 // instantiate it within the onCreate method
 4 mProgressDialog = new ProgressDialog(YourActivity.this);
 5 mProgressDialog.setMessage("A message");
 6 mProgressDialog.setIndeterminate(true);
 7 mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
 8 mProgressDialog.setCancelable(true);
 9 // execute this when the downloader must be fired
10 final DownloadTask downloadTask = new DownloadTask(YourActivity.this);
11 downloadTask.execute("the url to the file you want to download");
12 mProgressDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
13     @Override
14     public void onCancel(DialogInterface dialog) {
15         downloadTask.cancel(true);
16     }
17 });

 

DownloadTask继承自AsyncTask,按照如下框架定义,你需要将代码中的某些参数替换成你自己的。

 1 // usually, subclasses of AsyncTask are declared inside the activity class.
 2 // that way, you can easily modify the UI thread from here
 3 private class DownloadTask extends AsyncTask<String, Integer, String> {
 4     private Context context;
 5     private PowerManager.WakeLock mWakeLock;
 6     public DownloadTask(Context context) {
 7         this.context = context;
 8     }
 9     @Override
10     protected String doInBackground(String... sUrl) {
11         InputStream input = null;
12         OutputStream output = null;
13         HttpURLConnection connection = null;
14         try {
15             URL url = new URL(sUrl[0]);
16             connection = (HttpURLConnection) url.openConnection();
17             connection.connect();
18             // expect HTTP 200 OK, so we don't mistakenly save error report
19             // instead of the file
20             if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) {
21                 return "Server returned HTTP " + connection.getResponseCode()
22                         + " " + connection.getResponseMessage();
23             }
24             // this will be useful to display download percentage
25             // might be -1: server did not report the length
26             int fileLength = connection.getContentLength();
27             // download the file
28             input = connection.getInputStream();
29             output = new FileOutputStream("/sdcard/file_name.extension");
30             byte data[] = new byte[4096];
31             long total = 0;
32             int count;
33             while ((count = input.read(data)) != -1) {
34                 // allow canceling with back button
35                 if (isCancelled()) {
36                     input.close();
37                     return null;
38                 }
39                 total += count;
40                 // publishing the progress....
41                 if (fileLength > 0) // only if total length is known
42                     publishProgress((int) (total * 100 / fileLength));
43                 output.write(data, 0, count);
44             }
45         } catch (Exception e) {
46             return e.toString();
47         } finally {
48             try {
49                 if (output != null)
50                     output.close();
51                 if (input != null)
52                     input.close();
53             } catch (IOException ignored) {
54             }
55             if (connection != null)
56                 connection.disconnect();
57         }
58         return null;
59     }

 

上面的代码只包含了doInBackground,这是执行后台任务的代码块,不能在这里做任何的UI操作,但是onProgressUpdate和onPreExecute是运行在UI线程中的,所以我们应该在这两个方法中更新progress bar。

接上面的代码:

 1 @Override
 2 protected void onPreExecute() {
 3     super.onPreExecute();
 4     // take CPU lock to prevent CPU from going off if the user
 5     // presses the power button during download
 6     PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
 7     mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
 8          getClass().getName());
 9     mWakeLock.acquire();
10     mProgressDialog.show();
11 }
12 @Override
13 protected void onProgressUpdate(Integer... progress) {
14     super.onProgressUpdate(progress);
15     // if we get here, length is known, now set indeterminate to false
16     mProgressDialog.setIndeterminate(false);
17     mProgressDialog.setMax(100);
18     mProgressDialog.setProgress(progress[0]);
19 }
20 @Override
21 protected void onPostExecute(String result) {
22     mWakeLock.release();
23     mProgressDialog.dismiss();
24     if (result != null)
25         Toast.makeText(context,"Download error: "+result, Toast.LENGTH_LONG).show();
26     else
27         Toast.makeText(context,"File downloaded", Toast.LENGTH_SHORT).show();
28 }

 

注意需要添加如下权限:

1 <uses-permission android:name="android.permission.WAKE_LOCK" />

 

二、在service中执行下载

在service中执行下载任务的麻烦之处在于如何通知activity更新UI。下面的代码中我们将用ResultReceiver和IntentService来实现下载。ResultReceiver允许我们接收来自service中发出的广播,IntentService继承自service,这IntentService中我们开启一个线程开执行下载任务(service和你的app其实是在一个线程中,因此不想阻塞主线程的话必须开启新的线程)。

 1 public class DownloadService extends IntentService {
 2     public static final int UPDATE_PROGRESS = 8344;
 3     public DownloadService() {
 4         super("DownloadService");
 5     }
 6     @Override
 7     protected void onHandleIntent(Intent intent) {
 8         String urlToDownload = intent.getStringExtra("url");
 9         ResultReceiver receiver = (ResultReceiver) intent.getParcelableExtra("receiver");
10         try {
11             URL url = new URL(urlToDownload);
12             URLConnection connection = url.openConnection();
13             connection.connect();
14             // this will be useful so that you can show a typical 0-100% progress bar
15             int fileLength = connection.getContentLength();
16             // download the file
17             InputStream input = new BufferedInputStream(connection.getInputStream());
18             OutputStream output = new FileOutputStream("/sdcard/BarcodeScanner-debug.apk");
19             byte data[] = new byte[1024];
20             long total = 0;
21             int count;
22             while ((count = input.read(data)) != -1) {
23                 total += count;
24                 // publishing the progress....
25                 Bundle resultData = new Bundle();
26                 resultData.putInt("progress" ,(int) (total * 100 / fileLength));
27                 receiver.send(UPDATE_PROGRESS, resultData);
28                 output.write(data, 0, count);
29             }
30             output.flush();
31             output.close();
32             input.close();
33         } catch (IOException e) {
34             e.printStackTrace();
35         }
36         Bundle resultData = new Bundle();
37         resultData.putInt("progress" ,100);
38         receiver.send(UPDATE_PROGRESS, resultData);
39     }
40 }

 

注册DownloadService

1 <service android:name=".DownloadService"/>

 

activity中这样调用DownloadService

1 // initialize the progress dialog like in the first example
2 // this is how you fire the downloader
3 mProgressDialog.show();
4 Intent intent = new Intent(this, DownloadService.class);
5 intent.putExtra("url", "url of the file to download");
6 intent.putExtra("receiver", new DownloadReceiver(new Handler()));
7 startService(intent);

 

使用ResultReceiver接收来自DownloadService的下载进度通知

 1 private class DownloadReceiver extends ResultReceiver{
 2     public DownloadReceiver(Handler handler) {
 3         super(handler);
 4     }
 5     @Override
 6     protected void onReceiveResult(int resultCode, Bundle resultData) {
 7         super.onReceiveResult(resultCode, resultData);
 8         if (resultCode == DownloadService.UPDATE_PROGRESS) {
 9             int progress = resultData.getInt("progress");
10             mProgressDialog.setProgress(progress);
11             if (progress == 100) {
12                 mProgressDialog.dismiss();
13             }
14         }
15     }
16 }

 

三、使用DownloadManager

其实这才是解决下载问题的终极方法,因为他使用起来实在是太简单了。可惜只有在GingerBread 之后才能使用。

先判断能不能使用DownloadManager:

 1 /**
 2  * @param context used to check the device version and DownloadManager information
 3  * @return true if the download manager is available
 4  */
 5 public static boolean isDownloadManagerAvailable(Context context) {
 6     try {
 7         if (Build.VERSION.SDK_INT < Build.VERSION_CODES.GINGERBREAD) {
 8             return false;
 9         }
10         Intent intent = new Intent(Intent.ACTION_MAIN);
11         intent.addCategory(Intent.CATEGORY_LAUNCHER);
12         intent.setClassName("com.android.providers.downloads.ui", "com.android.providers.downloads.ui.DownloadList");
13         List<ResolveInfo> list = context.getPackageManager().queryIntentActivities(intent,
14                 PackageManager.MATCH_DEFAULT_ONLY);
15         return list.size() > 0;
16     } catch (Exception e) {
17         return false;
18     }
19 }

 

如果能,那么只需要这样就可以开始下载一个文件了:

 1 String url = "url you want to download";
 2 DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url));
 3 request.setDescription("Some descrition");
 4 request.setTitle("Some title");
 5 // in order for this if to run, you must use the android 3.2 to compile your app
 6 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
 7     request.allowScanningByMediaScanner();
 8     request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
 9 }
10 request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, "name-of-the-file.ext");
11 // get download service and enqueue file
12 DownloadManager manager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE);
13 manager.enqueue(request);

 

下载的进度会在消息通知中显示。

总结

前两种方法需要你考虑的东西很多,除非是你想完全控制下载的整个过程,否则用最后一种比较省事。

Demo下载

 

转载于:https://www.cnblogs.com/liangstudyhome/p/4138702.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/420431.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

前端学习(1293):系统模块path路径操作

//导入path模块 const path require(path); //路径拼接 const finaPath path.join(public, uploads, avater); console.log(finaPath); 运行结果

nacos作为服务注册中心

nacosnacos简介nacos 作为服务注册中心demo基于Nacos的服务提供者基于Nacos的服务消费者nacos切换ap和cp 模式nacos简介 为什么叫nacos 前四个字母分别为Naming和Configuration的前两个字母&#xff0c;最后的s为Service。是什么 一个更易于构建云原生应用的动态服务发现&am…

前端学习(1294):相对路径和绝对路径

const fs require(fs); const path require(path); console.log(__dirname); console.log(path.join(__dirname, ./demo01.js)); fs.readFile(path.join(__dirname, ./demo01.js), utf8, (err, doc) > {console.log(err);console.log(doc); }) 运行结果

layui 数据表格代码

一套增删改查&#xff0c;打完收工。 layui版本&#xff1a;2.4.5 默认请求,分页。 /rest_address?page1&limit1json数据格式要求. 参数说明文档 https://www.layui.com/doc/modules/table.html#cols <!DOCTYPE html> <html lang"en" xmlns:th"…

[BZOJ 1085] [SCOI2005] 骑士精神 [ IDA* 搜索 ]

题目链接 : BZOJ 1085 题目分析 : 本题中可能的状态会有 (2^24) * 25 种状态&#xff0c;需要使用优秀的搜索方式和一些优化技巧。 我使用的是 IDA* 搜索&#xff0c;从小到大枚举步数&#xff0c;每次 DFS 验证在当前枚举的步数之内能否到达目标状态。 如果不能到达&#xff0…

nacos服务配置中心演示

config centerNacos作为配置中心-基础配置Nacos作为配置中心-分类配置nacos将配置持久化到mysql新型技术&#xff0c;替代spring config center & bus Nacos作为配置中心-基础配置 ⑴ module cloudalibaba-config-nacos-client3377 (2) pom <dependencies><!--n…

前端学习(1296):第三方模块nodemon

修改保存重新执行 如何断开ctrlc

core java 8~9(GUI AWT事件处理机制)

MODULE 8 GUIs--------------------------------GUI中的包&#xff1a; java.awt.*; javax.swing.*; java.awt.event.*; 要求:1)了解GUI的开发流程&#xff1b;2&#xff09;掌握常用的布局管理器 开发GUI图形界面的步骤-------------------------------1.选择容器 1&#xff0…

note.. redis五大数据类型

redis 五大数据类型使用nosql介绍&#xff0c;由来什么是nosql阿里巴巴的架构nosql 四大分类redis入门概述redis 安装 &#xff08;docker&#xff09;基础的知识redis五大数据类型Redis-KeyStringList (列表)Set &#xff08;集合&#xff09;Hash(哈希)Zset 有序集合nosql介绍…

Arcengine 基本操作(待更新)

/// <summary>/// 删除fieldName属性值为1的弧段/// </summary>/// <param name"fieldName"></param>/// <param name"t"></param>public void DelectPolyline(string fieldName, int t){ILayer pLayer axMapControl…

redis 三种特殊数据类型

三种特性数据类型 geospatial 定位&#xff0c;附近的人&#xff0c;打车距离计算。 redis的geo在redis3.2版本就推出了。可推算地理位置的信息&#xff0c;两地之间的距离&#xff0c;方圆几里的人。 6个命令。 GEOADD GEODIST GEOHASH GEOPOS GEORADIUS GEORADIUSBYMEMB…

前端学习(1298):gulp使用

第一步安装 第二步建立文件夹 第三部 src放源代码 第四步 输入代码 执行

Sentinel 分布式系统的流量防卫兵

sentinelsentinel base服务编写关键名词解释sentinel base 官网&#xff1a; https://github.com/alibaba/Sentinel https://github.com/alibaba/Sentinel/wiki/%E4%BB%8B%E7%BB%8D 是什么&#xff1f; 是一款优秀的限流&#xff0c;降级&#xff0c;熔断的框架。 Sentinel …

php查询mysql返回大量数据结果集导致内存溢出的解决方法

web开发中如果遇到php查询mysql返回大量数据导致内存溢出、或者内存不够用的情况那就需要看下MySQL C API的关联,那么究竟是什么导致php查询mysql返回大量数据时内存不够用情况&#xff1f; 答案是: mysql_query 和 mysql_unbuffered_query 两个函数 首先来分析一个典型的实例:…

前端学习(1299):gulp插件

第一步 下载 第二步 const gulp require(gulp); const htmlmin require(gulp-htmlmin);gulp.task(first, () > {console.log(第一次执行);}); gulp.task(htmlmin, () > {gulp.src(./src/*.html)//压缩去其中的代码.pipe(htmlmin({ collapseWhitespace: true })).pipe(…

前端学习(1300)报错:无法加载文件 D:\nodejs\node_global\webpack.ps1,因为在此系统上禁止运行脚本...

解决报错&#xff1a; &#xff08;1&#xff09;以管理员身份运行命令行设置即可 &#xff08;2&#xff09;在终端执行&#xff1a;get-ExecutionPolicy&#xff0c;显示Restricted&#xff08;表示状态是禁止的&#xff09; &#xff08;3&#xff09;在终端执行&#xff…

动态规划系列 | 最长上升子序列模型(上)

文章目录 最长上升子序列回顾题目描述问题分析程序代码复杂度分析 怪盗基德的滑翔翼题目描述输入格式输出格式 问题分析程序代码复杂度分析 登山题目描述输入格式输出格式 问题分析程序代码复杂度分析 合唱队形题目描述输入格式输出格式 问题分析程序代码复杂度分析 友好城市题…