热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

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

原文地址:http:jcodecraeer.comaanzhuokaifaandroidkaifa201411252057.html这里主要讨论三种方式:AsyncTask、Ser

原文地址: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 {
 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 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下载

 


推荐阅读
  • 本文介绍了如何使用C#制作Java+Mysql+Tomcat环境安装程序,实现一键式安装。通过将JDK、Mysql、Tomcat三者制作成一个安装包,解决了客户在安装软件时的复杂配置和繁琐问题,便于管理软件版本和系统集成。具体步骤包括配置JDK环境变量和安装Mysql服务,其中使用了MySQL Server 5.5社区版和my.ini文件。安装方法为通过命令行将目录转到mysql的bin目录下,执行mysqld --install MySQL5命令。 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • Spring特性实现接口多类的动态调用详解
    本文详细介绍了如何使用Spring特性实现接口多类的动态调用。通过对Spring IoC容器的基础类BeanFactory和ApplicationContext的介绍,以及getBeansOfType方法的应用,解决了在实际工作中遇到的接口及多个实现类的问题。同时,文章还提到了SPI使用的不便之处,并介绍了借助ApplicationContext实现需求的方法。阅读本文,你将了解到Spring特性的实现原理和实际应用方式。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • XML介绍与使用的概述及标签规则
    本文介绍了XML的基本概念和用途,包括XML的可扩展性和标签的自定义特性。同时还详细解释了XML标签的规则,包括标签的尖括号和合法标识符的组成,标签必须成对出现的原则以及特殊标签的使用方法。通过本文的阅读,读者可以对XML的基本知识有一个全面的了解。 ... [详细]
  • 本文介绍了南邮ctf-web的writeup,包括签到题和md5 collision。在CTF比赛和渗透测试中,可以通过查看源代码、代码注释、页面隐藏元素、超链接和HTTP响应头部来寻找flag或提示信息。利用PHP弱类型,可以发现md5('QNKCDZO')='0e830400451993494058024219903391'和md5('240610708')='0e462097431906509019562988736854'。 ... [详细]
  • 前景:当UI一个查询条件为多项选择,或录入多个条件的时候,比如查询所有名称里面包含以下动态条件,需要模糊查询里面每一项时比如是这样一个数组条件:newstring[]{兴业银行, ... [详细]
  • 本文介绍了iOS数据库Sqlite的SQL语句分类和常见约束关键字。SQL语句分为DDL、DML和DQL三种类型,其中DDL语句用于定义、删除和修改数据表,关键字包括create、drop和alter。常见约束关键字包括if not exists、if exists、primary key、autoincrement、not null和default。此外,还介绍了常见的数据库数据类型,包括integer、text和real。 ... [详细]
  • Imtryingtofigureoutawaytogeneratetorrentfilesfromabucket,usingtheAWSSDKforGo.我正 ... [详细]
  • android listview OnItemClickListener失效原因
    最近在做listview时发现OnItemClickListener失效的问题,经过查找发现是因为button的原因。不仅listitem中存在button会影响OnItemClickListener事件的失效,还会导致单击后listview每个item的背景改变,使得item中的所有有关焦点的事件都失效。本文给出了一个范例来说明这种情况,并提供了解决方法。 ... [详细]
  • t-io 2.0.0发布-法网天眼第一版的回顾和更新说明
    本文回顾了t-io 1.x版本的工程结构和性能数据,并介绍了t-io在码云上的成绩和用户反馈。同时,还提到了@openSeLi同学发布的t-io 30W长连接并发压力测试报告。最后,详细介绍了t-io 2.0.0版本的更新内容,包括更简洁的使用方式和内置的httpsession功能。 ... [详细]
  • CF:3D City Model(小思维)问题解析和代码实现
    本文通过解析CF:3D City Model问题,介绍了问题的背景和要求,并给出了相应的代码实现。该问题涉及到在一个矩形的网格上建造城市的情景,每个网格单元可以作为建筑的基础,建筑由多个立方体叠加而成。文章详细讲解了问题的解决思路,并给出了相应的代码实现供读者参考。 ... [详细]
  • springmvc学习笔记(十):控制器业务方法中通过注解实现封装Javabean接收表单提交的数据
    本文介绍了在springmvc学习笔记系列的第十篇中,控制器的业务方法中如何通过注解实现封装Javabean来接收表单提交的数据。同时还讨论了当有多个注册表单且字段完全相同时,如何将其交给同一个控制器处理。 ... [详细]
  • [大整数乘法] java代码实现
    本文介绍了使用java代码实现大整数乘法的过程,同时也涉及到大整数加法和大整数减法的计算方法。通过分治算法来提高计算效率,并对算法的时间复杂度进行了研究。详细代码实现请参考文章链接。 ... [详细]
author-avatar
小东东5201314
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有